Просмотр поста

.
Delphinum
Инициализация приложения
Вся логика фреймворка, его архитектурные ограничения и возможности мы опишем в файле app/App.php. Этот файл очень важен, так как именно он отвечает за инициализацию всего приложения и доступ к его частям, но чтобы вам было проще понять как он выполняет свои функции, рассмотрим его составные части последовательно.

Для начала рассмотрим структуру класса инициализации:
<?php
// Файл app/App.php
require('vendor/autoload.php');
use Bricks\Autoload\Loader;
use Bricks\ServiceLocator\Manager;
use Bricks\Http\Routing\Router;
use Bricks\Http\Routing\Request;
use Bricks\Http\Routing\Response;

class App{
  public function run(){
    ...
  }
}


В классе подключается автозагрузчик зависимостей, создаваемый Composer, а затем объявляются все используемые в нем классы пакетов Bricks. Структура самого класса App довольно проста. Он не относится к какому либо пространству имен (namespace), так как это единственный модуль в приложении. В нем реализуется единственный метод run, который и вызывается из файла public/index.php и инициализирует приложение в целом.

Рассмотрим реализацию метода run. В первую очередь в нем необходимо подключить и настроить автозагрузчик, так как он используется всеми компонентами приложения:
public function run(){
  $loader = new Loader;
  $loader->pref('conf', 'app/conf');   // Конфигурации ищем в app/conf
  $loader->pref('model', 'app/model'); // Бизнес-логику в app/model
  $loader->pref('controller', 'app/controller'); // а контроллеры в app/controller
  ...
}

Думаю здесь комментарии излишни.

Далее необходимо заполнить инициализировать локатор служб. Этот механизм позволит всем частям приложения получить доступ к доступным компонентам фреймворка:
public function run(){
  // Автозагрузчик

  $locator = new Manager;

  $router = new Router; // Создадим роутер предварительно, чтобы его можно было добавить в локатор служб.

  $locator->set('loader', $loader); // В локатор добавляется автозагрузчик
  $locator->set('router', $router); // роутер
  $locator->set('conf', array_merge($loader->load('conf\global.conf'), $loader->load('conf\local.conf'))); // и конфигурации приложения.
  ...
}


Теперь самое интересное - настройка роутинга:
public function run(){
  // Автозагрузчик
  // Локатор служб

  // Обработка запросов вида http://site.com/controller/action
  $router->all('~^/([A-Za-z0-9_]+)/([A-Za-z0-9_]+)~',
    function(Request $request, Response $response, array $match) use($locator){
      list($subject, $action) = $match; // Определяем целевой контроллер и метод.
      $controller = 'controller\\' . ucfirst($subject); // Так как мы определили в автозагрузчике местонахождение всех контроллеров, его будет легко подключить.
      $controller = new $controller; // Создаем экземпляр контроллера
      $method = $action . 'Action';  // и определяем имя целевого метода как "имяAction"

      return $controller->$method($request, $response, $match); // Вызываем метод контроллера возвращая результат его работы.
    }
  );
  ...
}

Этот маршрут подходит для запросов на адрес вида: http://site.com/controller/action - но этого недостаточно, необходимо так же определить маршрут для запросов на адрес без URI: http://site.com - что мы и сделаем:
public function run(){
  // Автозагрузчик
  // Локатор служб
  // Маршрут A

  // Все запросы без URI передаем в контроллер controller\Index::indexAction
  $router->all('~^/?$~',
    function(Request $request, Response $response, array $match) use($locator){
      $controller = new controller\Index;
      return $controller->indexAction($request, $response, $match);
    }
  );
  ...
}


Осталось только выполнить маршрутизацию:
public function run(){
  // Автозагрузчик
  // Локатор служб
  // Маршрут A
  // Маршрут B

  $request = new Request;
  $response = new Response;
  $response->header('Content-Type', 'text/html;charset=utf-8'); // Определяем тип ответа как HTML-документ в кодировке UTF-8.
  $content = $router->run($request, $response); // Выполняем маршрутизацию и получаем ответ контроллера.
  include($loader->path('app/layout', 'html')); // Загружаем используемый нами шаблон страницы. Так как ответ контроллера записан в переменную $content, он будет вставлен в тело шаблона автоматически.
  $response->send(); // Отправляем ответ клиенту.
}


Полный листинг класса App приведен здесь:
App (+/-)


Архив с примером.