Tag Archives: Zf

ZendFramework, PoEdit и phtml файлы.

Одним из самых удобных способов локализации приложения, по моему мнению, является использование po/mo файлов с переводами, которые генерирует допотопная программа poedit, лучшей к сожалениею не написали :-(

Так вот, если вы прописали правильно пути к базе файлов которые нужно сканировать, ключевые слова выставлены верно, но программа не находит слова, которые находятся скажем в файлах с расширением отличных от стандартных (пример: php контент в файле *.phtml, что свойственно шаблонам вида в ZF).

Нашел вот здесь: http://web-blog.org.ua/articles/zend-framework-localizatsiya-proektov-chast-tretyaya хорошее описание и решение проблеммы. На всяк случай продублирую вкратце и у себя:

  1. Файл — Установки — Парсеры — PHP — Править
  2.  изменяем строку с расширениями на эту: *.php;*.phtml
  3.  изменяем строку с командой вызова на эту: xgettext —language=PHP —force-po -o %o %C %K %F

Подробнее в блоге по ссылке выше.

Zend Framework: разделение проекта на Core-Custom

Если вам нужно будет разделить проект на две части: ядро и кастом (например если многие части кода используются для нескольких проектов), то одним из вариантов решения такой задачи будет использовать ядро как и раньше, а все что отличается веносить в папки типа Project_custom/application|configs|models и так далее.

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

Для моделей это легко делается правильной настройкой аутолоадера, а точнее даже просто прописать include_paths в правильном порядке.

А вот с контроллерами было сложнее. В конфиге одному модулю можно задать только один путь. А вешать кастомные контроллеры на отдельный модуль в итоге не давало бы возможности перезаписывать стандартные контроллеры.

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

class Plugin_CustomController extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$front = Zend_Controller_Front::getInstance();
$dispatcher = $front->getDispatcher();
// здесь указываем путь к кастом контроллерам
$dispatcher->setControllerDirectory(APPLICATION_CUSTOM_PATH.’/controllers’);
if (!$dispatcher->isDispatchable($request))
$dispatcher->setControllerDirectory(APPLICATION_PATH.’/controllers’);   // а здесь контроллеры ядра
}
}

И в бутстрапе подключаем плагин:

Zend_Controller_Front::getInstance()->registerPlugin(new Plugin_CustomController());

Так же еще сходу не знал как сделать возможность перебивания layout-ов, но для них все оказалось еще проще — просто в конфиге проекта указать следующее:

‘resources’ => array(

‘layout’            => array(‘layoutPath’ => array(APPLICATION_PATH.’/layouts/scripts/’, APPLICATION_CUSTOM_PATH.’/layouts/’)),

)

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

Так само указывается путь для подключения скриптов вида:

array(‘resources’ => array(

‘view’ => array(
‘scriptPath’ => array(APPLICATION_PATH.’/views/scripts/’,APPLICATION_CUSTOM_PATH.’/views/scripts/’),
));

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

  1. создать один массив resourceTypes с описанием неймспейсов и путей к папкам нужным;
  2. создать два Zend_Loader_Autoloader_Resource в первом путь basePath задать к кастомной части, во втором к core файлам, resourceTypes в этих автозагрузчиках поставить одинаковым;
  3. для Zend_Loader_Autoloader сделать поочередно pushAutoloader сначала для кастом части, а затем для ядра;
  4. правильность подключения файлов без заковыристых namespace-ов обеспечивается указанием includePaths  в правильной последовательности: сначала путь к кастом части, затем к ядру.

Note: не забудьте убрать затем все include/require — это поломает логику правильных автолоадов файлов =)

Тонкости работы Zend_Autoloader

Если возникает задача использовать классы без неймспейсов( например Stat, Config и т.п. — без неймспейса, Model_Stat, Custom_Logger — с неймспейсами), то в ZF это вызовет трудности.

В результате копания кода найдено такое решение:

$autoloader->registerNamespace($namespaces)
->pushAutoloader($autoloader->getDefaultAutoloader(), '') // add loader for non namespaced classes
->pushAutoloader($resourceLoader, $namespaces);

Здесь «->pushAutoloader($autoloader->getDefaultAutoloader(), »)»  регистрирует пустой неймспейс и а ниже регистрируются заполненные неймспейсы.

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

Такой день.

Трудноуловимая ошибка с Zend_Loader_Autoloader::$_instance и доступом к контантам класса.

Продолжаю серию увлекательных особенностей ZF и PHP в общем.

Итак, если по неизвестной закономерности у вас возникает ошибка Access to undeclared static property: Zend_Loader_Autoloader::$_instance или же происходит Fatal error с ошибкой «обращение к несуществующей переменной» (что то типа Fatal error: Access to undeclared static property: Zend_Loader_Autoloader::$_instance in) , а в коде это выглядит типа как self::MYCONST то эта запись для вас.

В общем написал я недавно класс Zend_Session_SaveHandler_Memcached что бы использовать его как сторэдж для сохранения сессий.

И поначалу вроде как все работало нормально, но потом по неизвестной закономерности начала появляться ошибка что скрипт обращается к несуществующей переменной. Естественно, константа в классе объявлена. Замена self на Zend_Session_SaveHandler_Memcached результата не дало, ровно как и обновление пхп со всеми модулями. При это еще после того как скрипт меняется, страница грузится нормально, без ошибок, а последующие загрузки вызывают эту ошибку.

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

В итоге установил что проблема в параметре apc.cache_by_default который задается в php.ini и который был включен на этом сервере, а на других (на которых и ошибки этой не было) данного парамера пхпинфо вообще не возвращал. Установка параметра в 0 соответственно решило проблему.

Такой день.

Так же вариант менее варварский, но мной лично не проверенный: http://stackoverflow.com/questions/7749198/getting-apc-to-play-nice-with-spl-autoload-register за ссылку спасибо Роману Яровому из комментариев.

Еще об особенностях работы SOAP

Нынче закончил работу над API сервером на SOAP и опишу еще один момент, с которым возможно столкнется еще кто-то.

Итак, в Zf работа Soap сервера основана на двух элементах — autoDiscover и собственно soap_server. Оба этих элемента расположены на сервере и ссылаются друг на друга. И вот особенность в том, что при получении запроса на выполнение функции от соап клиента просходит запрос с soap_server на autoDiscover (адреса одного и другого указываются в самом сервере). Проблема, из-за которой пришлось потратить около часа на поиск решения проблемы была в том, что соап клиент возвращал:

Fatal error: Uncaught SoapFault exception: [WSDL] SOAP-ERROR: Parsing WSDL: Couldn’t load from ‘https://[censored]’ : failed to load external entity [url]

Сразу просто не догадался искать проблему на сервере, т.к. ошибку то возвращает клиент. Но как оказалось, он просто перетранслирует ошибку, которую возвращает сервер. А сервер ругался из-за того, что php был без модуля openssl. В общем в итоге доставление php5-openssl решило проблему.