Создаем свою CMS на PHP и MySQL. Часть 7

16.12.2012

В предыдущем уроке серии мы начали процесс добавления функционала категорий в нашу простую CMS. Рассмотрим, что нужно поменять в коде классов для реализации задуманных изменений.

Создание класса Category


Также как ранее мы создавали класс Article для управления хранением и выводом статей, нам нужно построить класс Category для решения таких же задач с категориями.

В папке cms имеется каталог classes. В каталоге classes создаем новый файл Category.php и копируем в него следующий код:

<pre><?php

/**
 * Класс для обработки категорий статей
 */

class Category
{
  // Свойства

  /**
  * @var int ID категории из базы данных
  */
  public $id = null;

  /**
  * @var string Название категории
  */
  public $name = null;

  /**
  * @var string Короткое описание категории
  */
  public $description = null;

  /**
  * Устанавливаем свойства объекта с использованием значений в передаваемом массиве
  *
  * @param assoc Значения свойств
  */

  public function __construct( $data=array() ) {
    if ( isset( $data['id'] ) ) $this->id = (int) $data['id'];
    if ( isset( $data['name'] ) ) $this->name = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['name'] );
    if ( isset( $data['description'] ) ) $this->description = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['description'] );
  }

  /**
  * Устанавливаем свойства объекта с использованием значений из формы редактирования
  *
  * @param assoc Значения из формы редактирования
  */

  public function storeFormValues ( $params ) {

    // Store all the parameters
    $this->__construct( $params );
  }

  /**
  * Возвращаем объект Category, соответствующий заданному ID
  *
  * @param int ID категории
  * @return Category|false Объект Category object или false, если запись не была найдена или в случае другой ошибки
  */

  public static function getById( $id ) {
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "SELECT * FROM categories WHERE id = :id";
    $st = $conn->prepare( $sql );
    $st->bindValue( ":id", $id, PDO::PARAM_INT );
    $st->execute();
    $row = $st->fetch();
    $conn = null;
    if ( $row ) return new Category( $row );
  }

  /**
  * Возвращаем все (или диапазон) объектов Category из базы данных
  *
  * @param int Optional Количество возвращаемых строк (по умолчаниюt = all)
  * @param string Optional Столбец, по которому сортируются категории(по умолчанию = "name ASC")
  * @return Array|false Двух элементный массив: results => массив с объектами Category; totalRows => общее количество категорий
  */

  public static function getList( $numRows=1000000, $order="name ASC" ) {
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "SELECT SQL_CALC_FOUND_ROWS * FROM categories
            ORDER BY " . mysql_escape_string($order) . " LIMIT :numRows";

    $st = $conn->prepare( $sql );
    $st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
    $st->execute();
    $list = array();

    while ( $row = $st->fetch() ) {
      $category = new Category( $row );
      $list[] = $category;
    }

    // Получаем общее количество категорий, которые соответствуют критериям
    $sql = "SELECT FOUND_ROWS() AS totalRows";
    $totalRows = $conn->query( $sql )->fetch();
    $conn = null;
    return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
  }

  /**
  * Вставляем текущий объект Category в базу данных и устанавливаем его свойство ID.
  */

  public function insert() {

    // У объекта Category уже есть ID?
    if ( !is_null( $this->id ) ) trigger_error ( "Category::insert(): Attempt to insert a Category object that already has its ID property set (to $this->id).", E_USER_ERROR );

    // Вставляем категорию
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "INSERT INTO categories ( name, description ) VALUES ( :name, :description )";
    $st = $conn->prepare ( $sql );
    $st->bindValue( ":name", $this->name, PDO::PARAM_STR );
    $st->bindValue( ":description", $this->description, PDO::PARAM_STR );
    $st->execute();
    $this->id = $conn->lastInsertId();
    $conn = null;
  }

  /**
  * Обновляем текущий объект Category в базе данных.
  */

  public function update() {

    // У объекта Category  есть ID?
    if ( is_null( $this->id ) ) trigger_error ( "Category::update(): Attempt to update a Category object that does not have its ID property set.", E_USER_ERROR );

    // Обновляем категорию
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "UPDATE categories SET name=:name, description=:description WHERE id = :id";
    $st = $conn->prepare ( $sql );
    $st->bindValue( ":name", $this->name, PDO::PARAM_STR );
    $st->bindValue( ":description", $this->description, PDO::PARAM_STR );
    $st->bindValue( ":id", $this->id, PDO::PARAM_INT );
    $st->execute();
    $conn = null;
  }

  /**
  * Удаляем текущий объект Category из базы данных.
  */

  public function delete() {

    // У объекта Category  есть ID?
    if ( is_null( $this->id ) ) trigger_error ( "Category::delete(): Attempt to delete a Category object that does not have its ID property set.", E_USER_ERROR );

    // Удаляем категорию
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $st = $conn->prepare ( "DELETE FROM categories WHERE id = :id LIMIT 1" );
    $st->bindValue( ":id", $this->id, PDO::PARAM_INT );
    $st->execute();
    $conn = null;
  }

}

?></pre>

Данный класс очень похож на класс Article и немного проще. Он содержит три свойства, которые соответствуют полям в таблице categories — id, name и description, конструктор __construct(), который создает новый объект Category. Также класс имеет метод storeFormValues() для сохранения данных из формы редактирования, методы для получения одной категории по ID и списка категорий, а также методов для вставки, обновления и удаления категории в базе данных.

Нам нужно включить новый класс Category в наши файлы кода, чтобы CMS могла получить доступ к нему. Поэтому включаем файл с классом в файл config.phpв папке cms, также как мы включали Article.php:

<pre><?php
ini_set( "display_errors", true );
date_default_timezone_set( "Australia/Sydney" );  // http://www.php.net/manual/en/timezones.php
define( "DB_DSN", "mysql:host=localhost;dbname=cms" );
define( "DB_USERNAME", "username" );
define( "DB_PASSWORD", "password" );
define( "CLASS_PATH", "classes" );
define( "TEMPLATE_PATH", "templates" );
define( "HOMEPAGE_NUM_ARTICLES", 5 );
define( "ADMIN_USERNAME", "admin" );
define( "ADMIN_PASSWORD", "mypass" );
require( CLASS_PATH . "/Article.php" );
require( CLASS_PATH . "/Category.php" );

function handleException( $exception ) {
  echo "Sorry, a problem occurred. Please try later.";
  error_log( $exception->getMessage() );
}

set_exception_handler( 'handleException' );
?></pre>

Модифицируем Article


Кроме создания  нового класса Category нужно также модифицировать класс  Article для работы с категориями. Ниже приводится код файла Article.php:

<pre><?php

/**
 * Класс для управления статьями
 */

class Article
{
  // Свойства

  /**
  * @var int ID статьи из базы данных
  */
  public $id = null;

  /**
  * @var int Дата публикации статьи
  */
  public $publicationDate = null;

  /**
  * @var int ID категории статьи
  */
  public $categoryId = null;

  /**
  * @var string Полное название статьи
  */
  public $title = null;

  /**
  * @var string Резюме статьи
  */
  public $summary = null;

  /**
  * @var string Содержание HTML статьи
  */
  public $content = null;

  /**
  * Устанавливаем свойства объекта с использованием значений из массива
  *
  * @param assoc Значения свойств
  */

  public function __construct( $data=array() ) {
    if ( isset( $data['id'] ) ) $this->id = (int) $data['id'];
    if ( isset( $data['publicationDate'] ) ) $this->publicationDate = (int) $data['publicationDate'];
    if ( isset( $data['categoryId'] ) ) $this->categoryId = (int) $data['categoryId'];
    if ( isset( $data['title'] ) ) $this->title = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['title'] );
    if ( isset( $data['summary'] ) ) $this->summary = preg_replace ( "/[^\.\,\-\_\'\"\@\?\!\:\$ a-zA-Z0-9()]/", "", $data['summary'] );
    if ( isset( $data['content'] ) ) $this->content = $data['content'];
  }

  /**
  * Устанавливаем свойства объекта с использованием значений из формы
  *
  * @param assoc Значения из формы
  */

  public function storeFormValues ( $params ) {

    // Сохраняем все параметры
    $this->__construct( $params );

    // Разбираем и сохраняем дату публикации
    if ( isset($params['publicationDate']) ) {
      $publicationDate = explode ( '-', $params['publicationDate'] );

      if ( count($publicationDate) == 3 ) {
        list ( $y, $m, $d ) = $publicationDate;
        $this->publicationDate = mktime ( 0, 0, 0, $m, $d, $y );
      }
    }
  }

  /**
  * Возвращаем объект Article соответствующий заданному ID
  *
  * @param int ID статьи
  * @return Article|false Объект Article или false, если запись не найдена или в случае другой ошибки
  */

  public static function getById( $id ) {
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "SELECT *, UNIX_TIMESTAMP(publicationDate) AS publicationDate FROM articles WHERE id = :id";
    $st = $conn->prepare( $sql );
    $st->bindValue( ":id", $id, PDO::PARAM_INT );
    $st->execute();
    $row = $st->fetch();
    $conn = null;
    if ( $row ) return new Article( $row );
  }

  /**
  * Возвращает все (или диапазон) объекты Article из базы данных
  *
  * @param int Optional Количество возвращаемых строк (по умолчанию = all)
  * @param int Optional Вернуть статьи только из категории с указанным ID
  * @param string Optional Столбц, по которому выполняется сортировка статей (по умолчанию = "publicationDate DESC")
  * @return Array|false Двух элементный массив: results => массив объектов Article; totalRows => общее количество строк
  */

  public static function getList( $numRows=1000000, $categoryId=null, $order="publicationDate DESC" ) {
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $categoryClause = $categoryId ? "WHERE categoryId = :categoryId" : "";
    $sql = "SELECT SQL_CALC_FOUND_ROWS *, UNIX_TIMESTAMP(publicationDate) AS publicationDate
            FROM articles $categoryClause
            ORDER BY " . mysql_escape_string($order) . " LIMIT :numRows";

    $st = $conn->prepare( $sql );
    $st->bindValue( ":numRows", $numRows, PDO::PARAM_INT );
    if ( $categoryId ) $st->bindValue( ":categoryId", $categoryId, PDO::PARAM_INT );
    $st->execute();
    $list = array();

    while ( $row = $st->fetch() ) {
      $article = new Article( $row );
      $list[] = $article;
    }

    // Получаем общее количество статей, которые соответствуют критерию
    $sql = "SELECT FOUND_ROWS() AS totalRows";
    $totalRows = $conn->query( $sql )->fetch();
    $conn = null;
    return ( array ( "results" => $list, "totalRows" => $totalRows[0] ) );
  }

  /**
  * Вставляем текущий объек Article в базу данных, устанавливаем его ID.
  */

  public function insert() {

    // Есть уже у объекта Article ID?
    if ( !is_null( $this->id ) ) trigger_error ( "Article::insert(): Attempt to insert an Article object that already has its ID property set (to $this->id).", E_USER_ERROR );

    // Вставляем статью
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "INSERT INTO articles ( publicationDate, categoryId, title, summary, content ) VALUES ( FROM_UNIXTIME(:publicationDate), :categoryId, :title, :summary, :content )";
    $st = $conn->prepare ( $sql );
    $st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );
    $st->bindValue( ":categoryId", $this->categoryId, PDO::PARAM_INT );
    $st->bindValue( ":title", $this->title, PDO::PARAM_STR );
    $st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );
    $st->bindValue( ":content", $this->content, PDO::PARAM_STR );
    $st->execute();
    $this->id = $conn->lastInsertId();
    $conn = null;
  }

  /**
  * Обновляем текущий объект Article в базе данных.
  */

  public function update() {

    // У объекта Article есть ID?
    if ( is_null( $this->id ) ) trigger_error ( "Article::update(): Attempt to update an Article object that does not have its ID property set.", E_USER_ERROR );

    // Обновляем статью
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $sql = "UPDATE articles SET publicationDate=FROM_UNIXTIME(:publicationDate), categoryId=:categoryId, title=:title, summary=:summary, content=:content WHERE id = :id";
    $st = $conn->prepare ( $sql );
    $st->bindValue( ":publicationDate", $this->publicationDate, PDO::PARAM_INT );
    $st->bindValue( ":categoryId", $this->categoryId, PDO::PARAM_INT );
    $st->bindValue( ":title", $this->title, PDO::PARAM_STR );
    $st->bindValue( ":summary", $this->summary, PDO::PARAM_STR );
    $st->bindValue( ":content", $this->content, PDO::PARAM_STR );
    $st->bindValue( ":id", $this->id, PDO::PARAM_INT );
    $st->execute();
    $conn = null;
  }

  /**
  * Удаляем текущий объект Article из базы данных
  */

  public function delete() {

    // У объекта Article есть ID?
    if ( is_null( $this->id ) ) trigger_error ( "Article::delete(): Attempt to delete an Article object that does not have its ID property set.", E_USER_ERROR );

    // Удаляем объект Article
    $conn = new PDO( DB_DSN, DB_USERNAME, DB_PASSWORD );
    $st = $conn->prepare ( "DELETE FROM articles WHERE id = :id LIMIT 1" );
    $st->bindValue( ":id", $this->id, PDO::PARAM_INT );
    $st->execute();
    $conn = null;
  }

}

?></pre>

Рассмотрим изменения в классе Article подробно:

  • Новое свойство categoryIdЧтобы установить соответствие статьи и категории мы добавили свойство categoryId для хранения ID категории, которой принадлежит статья. Также мы модифицировали конструктор __construct() для сохранения нового свойства categoryId в только что созданных объектах Article.
  • Изменение метода getList()Первоначальный вариант метода getList() возвращал все статьи в базе данных (или заданное количество записей). Так как нам нужно, чтобы CMS выводила список статей в определенной категории, модифицируем метод getList() для принятия опционального аргумента  $categoryId. Если он задан, то возвращаются статьи только из указанной категории.Если задан $categoryId, создаем строку $categoryClause для выражения WHERE, чтобы вернуть только те статьи, в которых значение поля categoryId соответствует значению categoryId. Затем модифицируем выражения SQL SELECT для включения переменной $categoryClause. Также добавляем новый вызов к$st->bindValue() для привязки заданного $categoryId.
  • Изменяем методы insert() и update()Также мы модифицировали методы класса Article  insert() и update() для работы с новым полемcategoryId. Изменили запросы SQL INSERT и UPDATE в каждом методе, и добавили новые вызовы кbindValue() для передачи свойства $categoryId в выражения SQL.

В следующем уроке серии мы изменим шаблоны клиентской и серверной частей для работы с категориями.

Источник урока: ruseller.com


  

Другие темы:

Фотошоп уроки для повышения мастерства
Сетевой маркетинг 2.0
YouTube Мастер 2014
Качественное видео в блог за час