Контент


[Ko3.3] Прочие изменения ядра

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

Правила именования файлов

  • Поддержка стандарта PSR-0 привела к тому, что все имена файлов классов в Kohana 3.3 должны начинаться с большой буквы. В регистрочувствительных системах (т.е. все кроме Windows) это важно.
  • Для корректной работы старых модулей, не приведенных к новому стандарту имен файлов, добавили метод Kohana::auto_load_lowercase(). Просто добавляете его к стандартному автозагрузчику в bootstrap.php и можно продолжать работать:

    spl_autoload_register(array('Kohana', 'auto_load_lowercase'));

  • Добавилась поддержка namespace‘ов в именах классов. Правила все те же — namespace (если он есть) будет преобразован в путь к классу, в качестве разделителей используется стандартный разделитель в PHP — ‘\\’.

CLI

  • Убрали класс CLI (был только метод CLI::options(), перенесен в Minion_CLI::options()). #3989
  • Из класса Kohana убрали статическое свойство $is_cli. Оно теперь не требуется, т.к. вся обработка CLI идет через модуль Minion.

класс Kohana (Kohana_Core)

  • Убрали свойство Kohana::$log_errors. Оно все равно не использовалось, при обработке исключений стандартным методом Kohana_Exception::_handler() лог теперь пишется. Осталось не забыть про логирование в своих обработчиках классов HTTP_Exception.
  • При инициализации ядра (метод Kohana::init()) добавили проверку на наличие подключенных логов и конфигов в свойствах Kohana::$log и Kohana::$config. Теперь можно спокойно добавлять свои обработчики логов/конфигов ДО вызова Kohana::init() и не бояться, что они пропадут.
  • Добавлен метод Kohana::version(), который просто возвращает строку с номером версии фреймворка и ее кодовым именем. Можно использовать для вывода информации где-нибудь в «подвале» сайта мааааленькими буквами.

Request

  • Request::factory() поменял перечень принимаемых параметров. Теперь он выглядит следующим образом:

    /**
     *
     * @param   string  $uri              URI of the request
     * @param   array   $client_params    An array of params to pass to the request client
     * @param   bool    $allow_external   Allow external requests? (deprecated in 3.3)
     * @param   array   $injected_routes  An array of routes to use, for testing
     * @return  void|Request
     */
    public static function factory($uri = TRUE, $client_params = array(), $allow_external = TRUE, $injected_routes = array())

    Исключен аргумент $cache, в котором можно было передать объект HTTP_Cache для кеширования запроса, вместо него добавили параметры $client_params и $allow_external (который только появился и уже объявлен deprecated).

    • По названию $client_params можно догадаться, что это параметры, которые будут переданы в Request_Client. На данный момент есть ограничение — будут использованы только те параметры, для которых есть одноименный сеттер в объекте Request_Client. Это ‘cache‘ (передаем объект HTTP_Cache), ‘follow‘ (булевский флаг, который разрешает или запрещает редирект), ‘follow_headers‘ (массив HTTP-заголовков, которые надо передать дальше после редиректа) и ‘strict_redirect‘ (если TRUE, то при 302 редиректе будет сохранен исходный метод HTTP-запроса, как того требует HTTP/1.1 — это поведение по умолчанию).

      Перечень параметров будет дорабатываться и расширяться. Например, сейчас в ветку 3.3/develop добавлены header_callbacks (#4353).

    • Параметр $allow_external позволяет запретить использование Request_Client_External, т.е. все поступающие запросы будут обработаны через Request_Client_Internal, как внутренние.
  • Убран метод response(), который позволял получить текущий объект Response.
  • Удален метод generate_etag(). В версии 3.2 это был дефолтный способ сгенерировать etag из содержимого Response объекта Request. В 3.3 класс Request уже не содержит свойство $_response, поэтому данный метод доступен только из класса Request.
  • Методы query() и post() поддерживают многомерные массивы (применяется Arr::path() вместо Arr::get()). Т.е. теперь можно использовать $request->query('foo.bar'), чтобы получить $_GET['foo']['bar'].

Роутинг

  • Фильтры. Одно из самых заметных нововведений. В 3.3 к каждому маршруту можно добавлять условия, влияющие на итоговые параметры маршрута (контроллер, экшен и т.д.). Более того, с помощью фильтров можно даже указать, что данный маршрут не подходит под предложенный URI. Приведу ниже несколько примеров, бессмысленных и беспощадных:

    Используем анонимную функцию, чтобы запретить использование маршрута:

    Route::set('default', '(<controller>(/<action>(/<id>)))')
    	->defaults(array(
    		'controller' => 'Welcome',
    		'action'     => 'index',
    	))->filter(function(Route $route, $params) {
    		if (Kohana::$environment === Kohana::PRODUCTION)
    			return false;
    	});

    Если мы хотим указать, что данный маршрут не подходит, то надо вернуть FALSE из фильтра.

    Вносим изменения в вычисленные параметры маршрута (меняем экшен в зависимости от используемого HTTP-метода):

    Route::set('default', '(<controller>(/<action>(/<id>)))')
    	->defaults(array(
    		'controller' => 'Welcome',
    		'action'     => 'index',
    	))->filter(function(Route $route, $params) {
    		$method = Request::current() ? Request::current()->method() : Arr::get($_SERVER, 'REQUEST_METHOD', HTTP_Request::GET);
    		switch($method)
    		{
    			case HTTP_Request::POST:
    				$params['action'] = 'create';
    				break;
    			case HTTP_Request::PUT:
    				$params['action'] = 'change';
    				break;
    			case HTTP_Request::DELETE:
    				$params['action'] = 'delete';
    				break;
    			default:
    				$params['action'] = 'show';
    		}
     
    		return $params;
    	});

    Обратите внимание, что необходимо вернуть массив параметров, если в него были внесены изменения. Если просто вернуть TRUE (или ничего не возвращать), то фильтр будет воспринят как прошедший проверку, но не поменявший параметры маршрута.

  • Иногда бывает необходимо объединить кешированные маршруты с уже зарегистрированными в системе. Для этого в метод Route::cache() добавили второй параметр $append. Если он выставлен в TRUE, то загруженные из кеша маршруты будет добавлены к существующим. В 3.2 они их полностью заменяли (впрочем, сейчас это осталось поведением по умолчанию).

Хэлперы

  • Исправлена работа метода Arr::get(), теперь он нормально обрабатывает NULL-значения в массиве. #4012
  • Добавлен метод Arr::set_path() для установки значения в многомерных массивах. Кроме того, Arr::extract() теперь работает с многомерными массивами (используются пути Arr::path() вместо ключей Arr::get()).
  • Arr::merge() теперь объединяет многомерные массивы без замены старого значения на новое. Это в первую очередь полезно при работе с конфигами. Пример можно посмотреть в #3141.
    Date::format_time() теперь принимает в качестве третьего (опционального) параметра идентификатор времЕнной зоны (timezone).
  • В хэлпер HTML добавили статическое свойство $strict. Если оно установлено в TRUE (по умолчанию), то сгенерированные элементы HTML будут содержать атрибуты в формате, принятом XHTML. Т.е. не
    <input type="checkbox" checked>

    а

    <input type="checkbox" checked="checked">

  • При записи лог-сообщения автоматически будет добавлена отладочная информация (tracelog, имя файла, номер строки и т.д.). А в методе Kohana::log() появился четвертый параметр $additional, в котором может содержаться различная полезная информация для записи в лог. В частности, если в $additional['exception'] сохранить объект Exception, то трейслог будет взят из него.
  • Логирование сделано более настраиваемым. В классах-потомках Log_Writer можно переопределить метод format_message(), чтобы установить свой формат текстовых сообщений в логах. Кроме того, добавились статические свойства Log_Writer::$timestamp и Log_Writer::$timezone, позволяющие указать формат даты и временнУю зону для логов.
  • Можно указать свой метод для сериализации или кодирования (обфускации) содержимого сессии. Если раньше использовался serialize() и base64_encode(), то теперь они вынесены в методы _serialize()/_unserialize()/_encode()/_decode(). То есть их можно переопределить, если вдруг понадобится.
  • Добавился метод Text::user_agent($agent, $value). Точнее, не добавился, а был вынесен из метода Request::user_agent($value). Он вычленял отдельный параметр из пользовательского User_Agent‘а (имя параметра передавалось в $value), а значение User_Agent бралось из Request. Сейчас метод стал более универсальным, в него надо передавать User_Agent явно (например, брать Request::$user_agent). Возможные значения $value:
    • ‘platform’ — имя операционной системы (‘Windows 7′, ‘Windows XP’, ‘FreeBSD’ и т.д.)
    • ‘browser’ — имя семейства браузеров (‘Internet Explorer’, ‘Opera’, ‘Firefox’ и т.д.)
    • ‘mobile’ — имя мобильного клиента (‘iPhone’, ‘Android’, ‘Opera mini’ и т.д.)
    • ‘robot’ — имя бота (‘Googlebot’, ‘Yahoo’, ‘Facebook’ и т.д.)

    Эти настройки берутся из конфиг-файла user_agents.php, и легко могут быть изменены под собственные нужды.

    Примеры использования:

    $agent = 'Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.18) Gecko/20110621 Fedora/3.6.18-1.fc14 Firefox/3.6.18';
    $data = Text::user_agent($agent, 'browser'); // 'Firefox'
    $data = Text::user_agent($agent, array('version', 'mobile')); // array('3.6.18', false)

  • В правило Valid::range() добавился 4-й параметр $step (1 по умолчанию). Т.е. теперь можно проверять значение на нахождение в диапазоне значений с произвольным шагом (к примеру, [1,3,5,7,9,11]).

Исключения

  • Добавлены классы для HTTP-кодов 300, 301, 302, 303, 304, 305, 307.
  • Исключения семейства классов HTTP_Exception теперь могут сообщить, какой Request из «выбросил». Используйте метод request() для получения этого объекта.
  • Исключения HTTP_Exception имеют встроенный валидатор, проверяющий достаточность переданных данных для успешной обработки исключения. Для этого реализован метод check(), в котором мы можем для любого исключения добавить собственную проверку. Вот так, к примеру, проверяются исключения класса HTTP_Exception_Redirect (коды 301-305, 307, 405):

    public function check()
    {
    	if ($this->headers('location') === NULL)
    		throw new Kohana_Exception('A \'location\' must be specified for a redirect');
     
    	return TRUE;
    }

Прочие изменения

  • Поправили PHPDOC, особенно в части указания правильных типов возвращаемых объектов.
  • Добавлены еще исключения в конфиг inflector.php.

UPD. Пока писал данную статью, вышел второй RC.

Google Bookmarks Digg Reddit del.icio.us Ma.gnolia Technorati Slashdot Yahoo My Web News2.ru БобрДобр.ru RUmarkz Ваау! Memori.ru rucity.com МоёМесто.ru Mister Wong

Опубликовано в Kohana3, Новости.

Теги: , , , .


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

Будьте в курсе обсуждения, подпишитесь на RSS ленту комментариев к этой записи.

  1. Dan пишет:

    Спасибо за статью
    надо посмотреть поподробнее на фильтры в роуте, до это статьи не знал про них.

  2. Vovochka пишет:

    Вот честно, если он так меняется каждые пол года, нужно ли оно?
    Как-то меня это разочаровывает…

  3. medar пишет:

    Огромное спасибо, Иван, что бы без тебя делали!

    Но, вообще, ситуация не радует. Чтобы юзать Кохану у себя в проектах приходится становиться специалистом по Кохане нескольких версий. И апдейтить сложно, и поддерживать на старых версиях сложно — надо быть в курсе, как какая конструкция пишется в разных версиях, если потребуется что-то дописать.

  4. biakaveron пишет:

    @Vovochka
    @medar
    А вас кто-то заставляет переходить на новые версии? :) Для 3.2 и 3.1 также правятся баги. Не уверен, что новые релизы для этих веток будут к выходу 3.3.0, но к лету наверняка выпустят.

  5. medar пишет:

    Ну тогда новые проекты придется тоже делать на 3.2 или 3.1, и вообще сидеть на этих ветках до скончания века. И через полгода или год, читая хэлп или какую-нить статью по кохане, вспоминать — есть ли такая функция в 3.2 или нет ?

    Меня иногда спрашивают, какой фреймворк юзать для php, и как-то Кохану язык не поворачивается рекомендовать. Несмотря на удобную внутреннюю структуру и т.п. Подсаживать человека на такое существование.. Это какой-то неправильный путь.

  6. biakaveron пишет:

    ИМХО, не все так плохо. Во-первых, в 3.3 не так уж много серьезных изменений, и переход с 3.2 должен быть довольно-таки простым. Единственное, что с PHP <5.3 возникнут проблемы. Ну и с модулями вечная проблема, это наверное главный минус.

    С другой стороны, если бы новые ветки релизились раз в пару лет, нашлись бы недовольные, что фреймворк плохо развивается.

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

  7. bagir пишет:

    Тоже никому не советую уже кохану. Текущие изменения, не очень как-то и обоснованы. Развитие никакого, а по факту сплошная модификация одного и того же.
    Сам же попробовал yii, сделал пол проекта на нем. По началу раза 3 хотел бросить и переделать на кохану, уж все казалось непривычно. И несмотря на наличие мануалов у уii многие детали не описаны. И сейчас уже понимаю, если писать что-то большое, что нужно постоянно поддерживать — определенно yii, для меленького проектика — kohana, и то очень спорный момент, так как yii и мелкие проекты переварит легко.

    В перспективе, есть желание попробовать симфони 2.

  8. medar пишет:

    А я тут недавно открыл для себя очень интересный фреймворк — laravel.com . Делает один человек, как и yii, только в отличие от yii он легкий и прозрачный. Меня он сразу подкупил.. наверное, это можно назвать здравым смыслом. Это как дух Рельсов на php. «Кто-то поработал головой». Миграции из коробки. Внятная валидация. Понятная короткая запись raw-запросов к базе, без «DB::query(Database::SELECT». Query Builder, ORM, но это у всех. Каталог бандлов-модулей, завязанный на гитхаб — прямо на официальном сайте. Сli-скрипт, для конфигурации, миграции, крона, юнит-тестов, установки и апгрейда бандлов и т.п. Как-то даже странно, что один человек за год сумел поднять все это с нуля, когда смотришь на то, что сделали разрабы Коханы за тот же год.

  9. rex пишет:

    Фильтры это отлично. Надо бы скачать и попробовать

  10. biakaveron пишет:

    @bagir
    Основные изменения в данной ветке больше похожи на рефакторинг, да. Правда, Minion весьма полезен, если говорить о новых фичах.

    UPD. Да что уж говорить, развитие всей третьей ветки как один сплошной рефакторинг )) Но, по крайней мере, к чему-то более-менее стабильному мы приходим.
    @medar
    Насколько я знаю, Yii только в самом начале один человек делал. Кстати, 3.0 тоже практически в одиночку была написана Вуди.

  11. Zares пишет:

    А вот я, ребят, ну что греха таить, ну очень хотел бы, чтобы все мои конкуренты писали на YII… ну, в крайнем случае, на Laravel или Fuel ;)

  12. SVat пишет:

    Мда, заглянул узнать что новенького в kohana, а в итоге ушел изучать laravel…

  13. Chodex пишет:

    Кохана не торт, ухожу постепенно на django.
    Хотя интересно что будет дальше, проекты поддерживать все-таки нужно

  14. Семен пишет:

    А мне нравится изменения) Люди не сидят сложа руки =)

  15. Spider пишет:

    А что с кэшированием роутов? Всё так же ошибки выдаёт о невозможности сериализации анонимных функций? Какой выход? Вообще роуты не кэшировать?

  16. biakaveron пишет:

    А какой может быть выход? Анонимки ведь не сериализуются. Если их отбрасывать, то кэширование получается ущербным. Правда, есть еще вот такой вариант — http://www.htmlist.com/development/extending-php-5-3-closures-with-serialization-and-reflection/

  17. Spider пишет:

    Ну хотя бы так:

    // Тут пишем роуты с функциями
     
    if ( ! Route::cache())
    {
      // тут пишем "обычные" роуты
      Route::cache(TRUE); // тут идёт проверка и все роуты с функциями выкидываются из кэша, если есть
    }

    Может это не самый красивый вариант, но думаю при желании можно что-то придумать :)

    Ссылка интересная, спасибо!

  18. biakaveron пишет:

    Кстати, автор того класса Super_Closure пишет на Kohana. Сейчас он оформил класс в виде целой библиотеки — https://github.com/jeremeamia/super_closure.

  19. seyfer пишет:

    Я ни где не могу найти примеры использования namespace в 3.3.

    Не будет трудно описать?

  20. seyfer пишет:

    Напоминаю о своей просьбе о namespace. Не могу разобраться как применить их в classes и использовать потом в контроллерах.

    …А если никак, то в чем отличие от 3.2 ?..

  21. biakaveron пишет:

    Использовать в обычных классах проблем нет:

    // файл classes/Foo/Bar.php
    namespace Foo;
     
    class Bar {
     
        public static function test()
        {
            return 'test';
        }
     
    }

    Потом просто \Foo\Bar::test().

    С контроллерами и моделями будет сложнее, так как в них есть префикс. Не обойтись без не очень красивого хака:

    // файл classes/Controller/Foo/Bar.php
    namespace Controller\Foo;
     
    class Bar extends \Controller {
     
        public function action_login()
        {
            $this->request->body('foo');
        }
    }
    // хак!
    class_alias('\Controller\Foo\Bar', 'Controller_Foo_Bar');

    Насколько я знаю, более красивого способа использовать namespace в контроллерах и моделях нет.



Можно включить подсветку кода: <code><pre lang="">...</pre></code>
Разрешены некоторые HTML теги

или используйте trackback.