CakePHP 1.2, Content-type, debug, RequestHandler и все-все-все

Как правильно, с точки зрения CakePHP, отвечать на запросы, если ответ требуется не html, а, например, json? Я считаю, что для получения ответа в нужном формате надо воспользоваться компонентом RequestHandler и указать в запросе расширение, в нашем случае ‘.json’. URL для запроса получится какой-то такой:

Чтобы Cake не пугался этого расширения и вызывал правильное действие (action), в файл APP/config/routes.php добавим строку:

Читать далее CakePHP 1.2, Content-type, debug, RequestHandler и все-все-все

Производительность pagination в CakePHP 1.2

Хотя использование разбивки на страницы (pagination) вполне заслуживает отдельного, обстоятельного поста, хочу остановиться лишь на паре не слишком очевидных моментов. Я предполагаю, что у читающих этот пост есть определенный навык использования CakePHP, моделей вообще и pagination в частности. Этот пост и так получается длинным.

Известно, что метод контроллера paginate() вызывает последовательно два метода модели — первый для подсчета общего числа записей, удовлетворяющих заданным условиям, и второй на выборку указанного числа записей начиная с заданной. Т.е. первый это фактически функция SQL COUNT(*), второй — SELECT … LIMIT n,m.

Именно из-за того, что вызовов методов больше одного, не срабаывает временная привязка/отвязка подчиненных моделей с помощью bindModel()/unbindModel(). Этим методам, для корректной работы с paginate() приходится передавать второй параметр, равный false. К счастью, еть ContainableBehavior, решающий эту проблему.

Эти запросы не всегда оптимальны и есть возможность улучшить производительность метода paginate() именно за счет оптимизации собственно самих запросов. Читать далее Производительность pagination в CakePHP 1.2

Методы модели findBy и findAllBy

В документации как-то очень мельком упомянуты эти методы. Кроме того описание этих методов выглядит так:

findBy<fieldName>(string $value)

Хотя на самом деле это не совсем соответствует действительности. Для поиска одной записи по значению одного поля описание должно выглядеть так:

findBy<fieldName>(string $value, $fields=null, $order=null, $recursive=null)

и

finAlldBy<fieldName>(string $value, $fields=null, $order=null, $limit=null, $page=null, $recursive=null)

Разница есть. Лично я очень обрадовался параметру $recursive — не надо отдельно, перед вызовом метода устанавливать это значение или ображаться к Containable.

Но и это еще не все! Читать далее Методы модели findBy и findAllBy

Добавляем правила проверки данных на лету

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

Во-первых правила проверки — это просто ассоциативный массив, в который вполне можно добавлять элементы, прямо из метода контроллера. Никуда они при инициализации модели, не парсятся и не обрабатываются, пока не будет вызван валидатор.

Во-вторых валидатор отлично справляется с полями формы, которым нет соответствия в модели. А метод модели save() записывает только те поля, которым соответствуют колонки в таблице.

Вот, например, простая форма регистрации пользователя. Читать далее Добавляем правила проверки данных на лету

Вечный логин

Используя встроенный в CakePHP компонент для аутентификации пользователей, AuthComponent, можно легко обеспечить возможность ввода логина и пароля до морковкиного заговения. :-)

Самым нетерпеливым раскрываю суть: запретите доступ неавторизованному пользователю к действию logout. :-)

Схема работы методов компонента простая. Если пользователь неавторизован, то URL, который он запрашивает сохраняется в сессии, а сам пользователь перенаправляется на страницу авторизации. При выходе (вызов метода logout) — все наоборот: запоминается referer, данные о пользователе убираются из сессии, он становится неавторизованным и перенаправляется обратно, на тот URL, с которого пришел.

Если неавторизованному пользователю запретить доступ к logout, при попытке обращения к этому действию, пользователь будет перенаправлен на страницу входа, наберет логин-пароль и отправится сразу на запрашиваемую им страницу с выходом, там его авторизация закончится и он снова будет отправлен на страницу входа…

Читать далее Вечный логин

SluggableBehavior — помощник в создании ЧПУ

После выхода стабильной версии CakePHP количество постов в разных блогах, посвященных этому фреймворку, сократилось. Даже в Bakery тишина. Либо Рождество с Новым годом, либо все, засучив рукава, занялись разработкой.

В помощь неутомимым пекарям я решил рассказать об удобном расширении модели (behavior). Вещь, на мой взгляд, полезная. Работает отлично, я этим behavior пользуюсь уже почти год. Он помогает автоматически, при записи, сгенерировать slug для строки таблицы.

Вот, кстати, мне всегда было интересно, как правильно перевести на русский слово slug в этом контексте. Ярлык?

Этот behavior написал Mariano Iglesias. Это часть его проекта Cake Syrup. О другой интересной составляющей, SoftDeletableBehavior, недавно, кстати, можно прочесть здесь.

Это расширение не использует Inflector::slug() — когда оно создавалось, этого метода еще не было. Зато поддержка транслита русских букв в UTF-8 уже встроена, не без помощи Вашего покорного слуги. ;-) Читать далее SluggableBehavior — помощник в создании ЧПУ

Рождественский пирог: долгожданный релиз CakePHP 1.2

К Рождеству разработчики CakePHP выпустили долгожданный релиз фреймворка версии 1.2. Разработка этой версии длилась почти 2 года и, надо сказать, пирог получился отменный! Что больше всего нравится лично мне:

  • Behaviors — расширение функционала моделей. PHP досих пор страдает отсутствием множественного наследования и behaviors в CakePHP очень технично эту проблему решают.
  • Тесты — CakePHP интегрируется с пакетом SimpleTest и позволяет создавать тесты для всех методов контроллеров и моделей. Это очень важно при разработке
  • Консольная утилита, позволяющая создавать типичные модели, контроллеры, каркас приложения и т.д. Очень удобная, на мой взгляд.
  • Законченная и понятная концепция плагинов. Части приложения, более-менее самостоятельные, можно изготавливать в виде плагинов и использовать в разных проектах.

Это, конечно, не полный список «вкусностей», а только то, что сразу вспомнилось. В целом, по сравнению с версией 1.1 фреймворк сильно изменился в лучшую сторону. Стал более понятным и удобным.

Читать далее Рождественский пирог: долгожданный релиз CakePHP 1.2

Производительность фреймворков — CodeIgniter уходит в отрыв

Хуан Бассо протестировал несколько современных версий популярных PHP-фреймворков. Увы, оба два моих предпочитаемых: CakePHP и ZendFramework слили CodeIgniter’у по полной программе. В лидерах оказался и неизвестный мне Yii.

Автор тестировал производительность 3-х приложений: стандартного ‘Hello, world’, запрос к базе данных на выборку 10 записей и запрос на выборку 1000 записей. Для тестирования использовался, как я понял, массовый бразильский сервер: Debian, PHP 5.2.0, MySQL 5.0, Apache 2.2.3, процессор Xeon 2.66G и 256 мегабайт оперативки. Всяческие хитрости типа Memcache были отключены и не использовались, все приложения запускались, как принято говорить, в production режиме, т.е. с отключенной отладочной информацией и тому подобное.

Тестовые приложения для каждого фреймворка были разработаны на основе документации, а не взяты из готовых примеров. Это, конечно, может наложить некоторый отпечаток, поскольку вряд-ли Хуан одинаково хорошо разбирается во всех пакетах, зато такой подход наглядно демонстрирует то, что можно получить, если завтра принять решение о смене фреймворка. :-)

В тесте принимали участие самые свежие версии:

Читать далее Производительность фреймворков — CodeIgniter уходит в отрыв

Самый последний CakePHP Release Candidate

Поскольку «последний перед финальный релизом» Candidate был RC3, то сегодня вышел вышел «последний-последний RC4». Авторы Cake, видимо, тоже подвержены приступам перфекционизма. Изменений, по сравнению с RC3 немного и моих проектов, они, кажется, не коснулись. Не то, что RC3.

  • Из компонента AclComponent убрали методы setAro(), setAco(), getAro() и getAco()
  • Убран метод Model::normalizeFindParams()
  • Из параметров метода JavascriptHelper::codeBlock() убран $safe, ранее отмеченный как deprecated
  • Изменен параметр вызова метода XmlNode::toArray(). Вместо $object (=null) теперь $camelize (= true)
  • Исправлены какие-то стили, скорее всего для вывода тестов или scaffold views. В общем, если пользуетесь стандартным файлом со стилями, сake.css, обновите его.
  • Методы ClassRegistry::_duplicate() и Router::matchRoute() теперь private, переименованы в ClassRegistry::__duplicate() и Router::__matchRoute() соответственно

M — for model

Очень-очень редко, но бывает нужно использовать в каком-нибудь методе контроллера несколько несвязанных между собой моделей. Еще раз, ключевые слова: «редко-редко» и «несвязанных».

Можно такие модели перечислить в переменной класса $uses — тогда, они, правда, будут загружаться для любого метода контроллера.

В версии 1.1 фреймворка была функция loadModel(), которая теперь отменена.

Есть еще метод requestAction(), но он объявлен «плохим». И правда, это, по сути, еще один запрос к приложению по полной программе, с диспетчеризацией, роутингом, стартом и инициализацией всех сопутствующих классов. В общем, путь неоптимальный и пользоваться им можно лишь от полной безысходности.

Можно воспользоваться методом App::import() — это хороший метод для многих классов. Но загруженная модель будет неполной. Т.е. это будет просто загруженный класс модели, без всех предварительных инициализаций самой модели и т.п. Этим методом лучше пользоваться для подгрузки своих классов или библиотек сторонних разработчиков.

В общем, я лично чаще всего в Cake 1.2 использовал именно App::import(), мирясь с некоторыми ограничениями. Но, оказывается есть еще один метод, позволяющий полностью загрузить модель, со всем ее «обвесом»

Читать далее M — for model