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

А именно — начать использовать менеджер зависимостей для PHP — Composer. Он позволит нам легко устанавливать разные полезные вещи на сайт, обновлять их и даже удалять. Если вы уже работали с менеджером пакетов GNU/Linux — то вам всё это будет очень знакомо.

В качестве разминки, удалим Fenom из директории core и установим через Composer. Для этого нужно в корне сайта создать файл composer.json и прописать в нём требуемые пакеты (подробнее можно прочитать на Хабре):
{
	"require": {
		"php":">=5.3.0",
		"fenom/fenom": "2.*"
	}
}
Теперь нужно только скачать composer.phar и запустить его в корне сайта:
php composer.phar install
На modhost.pro и качать ничего не нужно — просто запускаем composer в директории:
composer install
И волшебным образом у нас появляется директория /vendor/ с установленным Fenom. Что же с ним делать дальше?

Принцип работы

Давайте немного остановимся, и я объясню, как именно функционирует Composer, если вы еще не знаете.

Composer — это менеджер пакетов, который работает с ними согласно правил в composer.json. То, что мы там напишем, и будет устанавливаться.

При установке пакетов Composer пробегается по их правилам и генерирует самый важный файл — /vendor/autoload.php, который загружает все скачанные классы. Нам, выходит, нужно только подключить этот файл в своём проекте, и с этих пор мы можем запускать свои классы без require:
$Fenom = new Fenom::factory($tplDir, $compileDir);
То есть, система уже знает, где физически находится Fenom и нам не нужно делать reuire_once('путь к fenom'). Также нам не нужно держать сам Fenom в своём проекте, достаточно хранить там наш composer.json.

Еще раз, для закрепления:
  1. Пишем composer.json
  2. Устанавливаем пакеты через composer.phar
  3. Подключаем в проект /vendor/autoload.php
  4. Используем любые установленные классы через new Class()
Лишних файлов в проекте нет, лишних require нет, установленные пакеты обновляются через тот же composer:
php composer.phar update
Всё очень просто и удобно. Стоит только раз использовать такую схему работы и велосипедить дальше уже просто невозможно!

Подключаем Fenom

Для работы с установленными пакетами нам нужно просто добавить autoload.php в наш класс Core:
	function __construct(array $config = array()) {
		$this->config = array_merge(
			array(
				'controllersPath' => dirname(__FILE__) . '/Controllers/',
				'templatesPath' => dirname(__FILE__) . '/Templates/',
				'cachePath' => dirname(__FILE__) . '/Cache/',
				'fenomOptions' => array(
					'auto_reload' => true,
					'force_verify' => true,
				),
			),
			$config
		);
		// Например, вот тут
		require_once dirname(dirname(__FILE__)) . '/vendor/autoload.php';
	}
Из метода getFenom() теперь можно выбросить проверку и подключение файлов, а также загрузку его классов. Итоговый метод выглядит так:
	public function getFenom() {
		if (!$this->fenom) {
			try {
				if (!file_exists($this->config['cachePath'])) {
					mkdir($this->config['cachePath']);
				}
				$this->fenom = Fenom::factory($this->config['templatesPath'], $this->config['cachePath'], $this->config['fenomOptions']);
			}
			catch (Exception $e) {
				$this->log($e->getMessage());
				return false;
			}
		}

		return $this->fenom;
	}
Просто вызываем Fenom::factrory — и он сам загрузится. Вот коммит с изменениями — смотрите, сколько кода мы убрали сразу из своего проекта!

Зачем нам таскать с собой Fenom и обновлять его вручную, если давно придуман Composer, который об этом позаботится гораздо лучше? Всё, что нам нужно — положить в корень проекта composer.json.

Давайте теперь отрефакторим и наш собственный проект, чтобы он также подключался в autoload.php.

Рефакторинг проекта

Вся эта замечательная автозагрузка работает при помощи пространств имён — namespaces. Это такая фишка для гарантированного отделения имён классов друг от друга. Все классы, как бы, лежат в своих виртуальных директориях, и чтобы их использовать, нужно указывать полное имя или задавать псевдоним. Подробнее можно снова прочитать на Хабре.

При этом, физически файлы должны быть разложены в таких же директориях, чтобы загрузчик знал где их искать. Как именно это работает расписано в официальных стандартах, но я вам советую проглядеть вот эту статью.

Отсюда следует два вывода: Composer можно использовать только в PHP 5.3+, и наш проект нужно переписать так, чтобы он использовал пространства имён.

Первым делом, нужно определить имя для нашего проекта. Пусть будет Brevis — от латинского «короткий». Теперь наша директория /core/ — это пространство имён Brevis. Значит:
  • Класс Core становится \Brevis\Core и находится в core\Core.php
  • Класс Controller становится \Brevis\Controller и находится в core\Controller.php
  • Класс Controlles_Home становится \Brevis\Controllers\Home и находится в core\Controllers\Home.php
  • Класс Controlles_Test становится \Brevis\Controllers\Test и находится в core\Controllers\Test.php
Обратите внимание, что физическое расположение файлов совпадает с пространством имён. Это потому, что мы уже следуем стандарту PSR-4.

Теперь в начале каждого класса пишем используемое пространство имён. У основных классов это:
<?php 
namespace Brevis;
А у контроллеров:
<?php 
namespace Brevis\Controllers;

PhpStorm сразу начинает подсвечивать нам все использования Exception и Fenom как неправильные, потому что они вызываются внутри пространства имён, но без указания полного имени. Тут 2 варианта исправления:
  1. Пробежаться по всему коду и добавить к именам этих классов \, чтобы было \Exception и \Fenom
  2. Не страдать фигнёй, а использовать псевдонимы — возможность указать короткое имя для класса
Конечно, выбираем второй вариант:
<?php 
namespace Brevis;

use \Fenom as Fenom;
use \Exception as Exception;
И ничего в коде менять не нужно — все вызовы Fenom теперь автоматически будут разрешены в \Fenom на этапе работы.

Теперь переименовываем контроллеры и указываем в них псевдонимы:
<?php
namespace Brevis\Controllers;

use Brevis\Controller as Controller;

class Home extends Controller {
Как видите, изменения кода совсем минимальные. У нас уже была верная структура для работы автозагрузчика, поэтому осталось всего несколько штрихов.

Перемещаем autoload.php из класса \Brevis\Core в index.php, потому что пространство имён Brevis у нас скоро и само будет работать через автозагрузку и лишние require ему не нужны.

Index.php теперь выглядит вот так:
require_once dirname(__FILE__) . '/vendor/autoload.php';
$Core = new \Brevis\Core();

$req = !empty($_REQUEST['q'])
	? trim($_REQUEST['q'])
	: '';
$Core->handleRequest($req);

Метод \Brevis\Core::handleRequest() переписываем, убирая всякие проверки файлов. Нам нужно проверять только наличие класса, используя get_class():
	public function handleRequest($uri) {
		$request = explode('/', $uri);

		$className = '\Brevis\Controllers\\' . ucfirst(array_shift($request));
		/** @var Controller $controller */
		if (!class_exists($className)) {
			$controller = new Controllers\Home($this);
		}
		else {
			$controller = new $className($this);
		}

		$initialize = $controller->initialize($request);
		if ($initialize === true) {
			$response = $controller->run();
		}
		elseif (is_string($initialize)) {
			$response = $initialize;
		}
		else {
			$response = 'Возникла неведомая ошибка при загрузке страницы';
		}

		echo $response;
	}
Как видите, мы определяем полное имя загружаемого контроллера, проверяем его наличие, а если такого контроллера нет — загружаем \Brevis\Controllers\Home.

В общем, вся логика осталась прежней, а количество кода сократилось. Нет ручной работы с файлами, нет никаких require, вся работа по подключению классов лежит на autoload.php. Соотвественно, и параметр controllersPath из системного конфига пропадает.

Осталось добавить и наш собственный проект в автозагрузку. Для этого меняем composer.json вот так:
{
  "name": "Brevis",
  "autoload": {
    "psr-4": {
      "Brevis\\": "core/"
    }
  },
  "require": {
    "php": ">=5.3.0",
    "fenom/fenom": "2.*"
  }
}
Блок autoload указывает, что загружать дополнительно, кроме установленных пакетов. Ключ psr-4 указывает, как именно загружать наш проект, и указывает директорию core/ как основную для пространства имён Brevis.

Запускаем
php composer.phar update
и наши классы попадают в автозагрузку. Всё должно работать, смотрим изменения на GitHub.

Заключение

Вот мы и переписали наш проект в соотвествии с последними стандартами в мире программирования на PHP. Согласитесь, было не так уж и страшно?

Зато теперь наш код чистенький, опрятненький, соотвествует стандартам и отлично работает!

На следующем занятии мы установим через Composer xPDO 3.0 (да-да, он уже переписан и поддерживает namespaces, хоть пока и только в dev-ветке) и подключим его к нашей БД.

Напишем схему, сгенерируем по ней модель и создадим пару таблиц.

Следующая заметка
Подключаем xPDO
Предыдущая заметка
Расширение и наследование шаблонов Fenom


Комментарии ()

  1. Семён Лобачевский 07 июня 2015, 18:19 # 0
    Спасибо за урок!
    Понял, что со стандартизацией и автоматизацией в разработке гораздо проще и удобней.
    1. Василий Наумкин 07 июня 2015, 18:33 # +1
      Согласен! Причём, чем больше используешь готовых пакетов, тем лучше это выглядит. Вот, вчера так за день переписал один проект — аж на душе полегчало!
    2. Семён Лобачевский 07 июня 2015, 18:32 # 0
      Вопрос по алгоритму работы приложения, как вы запоминаете что и с чем взаимодействует? Какие классы и методы нужны в том или ином случае?
      Я так подозреваю, что для создания даже такого мини фреймворка, всё равно требуется сначала составить логику работы этого фреймворка или всё проще?
      1. Василий Наумкин 07 июня 2015, 18:36 # 0
        А не нужно ничего запоминать — всё подскажет PhpStorm. Для того мы и пишем ему комментарии у методов и переменных, чтобы быстро переходить по ним. Вся работа разбивается на отдельные мелкие методы, помещается в контроллеры и запутаться сложно.

        Ну а в целом, всегда есть любимые решения:
        — Fenom для шаблонизации
        — xPDO для работы с БД
        — PhpMailer для почты
        — Parsedown для работы с Markdown.

        Если понадобится что-то еще, просто гуглю, смотрю документацию и устанавливаю через Composer. Не понравилось — удаляю и ищу что-то новое.
      2. Сергей 22 сентября 2015, 20:30 # 0
        Теперь нужно только скачать composer.phar и запустить его в корне сайта:
        php composer.phar installНа modhost.pro и качать ничего не нужно — просто запускаем composer в директории:
        composer install
        Вот тут непонятно… каким образом запустить?
        1. Василий Наумкин 23 сентября 2015, 03:10 # 0
          Зайти в консоль сервера, перейти в директорию с проектом и набрать
          composer install
          1. Сергей 23 сентября 2015, 09:09 # 0
            Василий, видимо я совсем новичок)) А как можно попасть в консоль сервера? — гуглил, выдает только консоль контрстрайка… У меня как раз modhost.pro.
            1. Василий Наумкин 23 сентября 2015, 09:21 # +1
              Вторая ссылка в Яндексе по запросу как можно попасть в консоль сервера.

              Имя пользователя, сервер и пароль для SSH показываются в окне информации сайта на modhost.
              1. Сергей 23 сентября 2015, 15:08 # 0
                Спасибо, буду разбираться!)
        2. Николай Савин 05 января 2016, 11:08 # 0
          Василий, А если у меня типовой виртуальный хостинг без доступа к консоли и ssh не будет работать? Есть ли альтернативные способы запустить установку Composer?
          Если нет, сильно ли мне это затруднит изучение дальнейших материалов курса?
          1. Василий Наумкин 05 января 2016, 11:18 # 0
            Честно говоря, виртуальный хостинг без консоли — это сегодня не совсем типовое. Бывает, что SSH отключен по умолчанию, но можно включить из панели управления.

            В принципе, можно скачать всё нужное из репозиториев на GitHub и залить на сервер, но через Composer, конечно, было бы в разы удобнее.

            Есть еще вариант запускать composer из php скрипта через браузер. Ну и можно, конечно, купить сайт для разработки на modhost.pro за 75 руб — там всё есть.
            1. Николай Савин 05 января 2016, 12:17 # 0
              Вот нашел скрипт NoConsoleComposer, который все устанавливает через бразузер. Может кому пригодится.
              Теперь осталось разобраться, что он мне там поустанавливал.
              1. Николай Савин 05 января 2016, 13:47 # 0
                В общем в итоге купил хостинг на modstore. Все установил, код переписал, с GitHub сверился, все нормально.
                Но почему то сайт не работает, и вот эта строка в конце урока
                php composer.phar update
                выдает ошибку Could not open file: composer.
                Видимо что то не туда положил, но в итоге застрял и что делать не знаю. Нужна подсказка.
                1. Василий Наумкин 05 января 2016, 14:01 # 0
                  У нас там всё проще:
                  composer update
                  И еще обрати внимание, что ты положил composer.json выше директории core (рядом с www), а не внутри. Так тоже можно, но нужно будет поменять путь к autoload.php.
                  1. Николай Савин 05 января 2016, 14:04 # 0
                    А вот этот файл .gitignore зачем нужен? Про него речи в уроке не было но в GitHub он есть.
            Добавление новых комментариев отключено.