Posts Tagged ‘Zend Framework’

Как вы используете Sphinx Search API?

Posted in Development, LinkAider, Projects, Sphinx Search, ZendFramework on December 21st, 2009 by Yaroslav Vorozhko – Be the first to comment

Sphinx Search API для PHP пердставляет собой единый класс, который позволяет использовать все возможности Sphinx Search через его интерфейс. Но, такой класс является удобным только для небольших скриптов и задач.
Для более сложных задач и больших веб приложений необходимо другое решение. И это решения является проектированием и реализацией собственной обертки для Sphinx Search API.

В нашем проекте LinkAider.com мы используем следующие понятия и классы при работе с Sphinx Search:

  1. Сфинкс клиент, отвечающий за подключение, выполнение запросов и обработку ошибок. Для разработчика сфинкс клиент невидим, мы только сообщаем ему параметры подключения к searchd.
  2. Сфинкс индекс – это один из основных классов, с которым работает разработчик, этот класс отвечает за формирование запросов и выполнение запросов через Сфинкс клиент, а также за обработку результатов запроса.
  3. Сфинкс запрос – это еще один класс к которому обращается разработчик для составления запросов. Каждый запрос отвечает за свои индекс к которому обращается, а также содержит свои фильтры, группировки, сортировки и собственно сам запрос.
  4. Сфинкс результат – это класс, который разбирает ответ сфинкса и предоставляет удобный интерфейс к информации по каждому запросу, также он содержит информацию об ошибках, которую испльзуетя Сфинкс клиент для логирования. Сфинкс результат используется разработчиками для создания запросов к базе данных и получения искомых данных.

Пример работы выглядит следующим образом:

  1. Мы создаем объект Сфинкс индекс, который инициализирует Сфинкс клиент, устанавливая для него параметры подключения.
  2. Потом мы создаем объекты запросы для каждого указываем фильтры, группировки и т.п., и указываем к какому индексу делать запрос. Запросов может быть один или несколько, несколько запросов обрабатываються паралельно, что улучшает общую производительность системы.
  3. Каждый созданный запрос мы добавляем в Сфинкс индекс, при добавлении мы можем также указатьк какому индексу делать запрос.
  4. Специальный метод Run класса Сфинкс индекс запускает все запросы и как результат возвращает нам объект Сфинкс результат.
  5. Данные из Сфинкс результата мы используем чтоб создать запросы к базе данных и получить искомые данные.

Преимущеста, которые мы получем от работы с такой библотекой – это простота. Разработчик используя объект Сфинкс запрос может выполнять любые запросы.
Сфинкс результат предоставляет удобную обертку над массивом результата.
Нет необходимости помнить множество констант SphinxClient и парсить массив результата. В общем это выглдит так, как будто вы работаете с обычной таблицой, но не до конца. :)

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

Решение я вижу, в привязке каждого запроса к определенной таблице или группе таблиц.

По описнной выше логике я разрабатываю модуль Sphinx Search для Zend Framework, который я планирую выложить в откртый доступ очень скоро, возможно к новому году.

Поэтому хотелось бы узнать как вы используете Sphinx Search и какие преимущества и недостатки вывидите у вашего подхода.

Буду рад любым советам и рекомендациям.

Простой загрузчик файлов для Zend Framework

Posted in Development, Tips And Tricks, ZendFramework on December 17th, 2009 by Yaroslav Vorozhko – Be the first to comment

Сегодня увидел хороший code snippet простого лоадера файлов в проект на Zend Framework.

CODE:
  1. class App_Application_Resource_Fileloader extends Zend_Application_Resource_ResourceAbstract {
  2.   /**
  3.    * @return null
  4.    */
  5.  
  6. public function init() {
  7.         $options = $this->getOptions ();
  8.         foreach ($options as $filePath)
  9.             include $filePath;
  10. return null;
  11.        
  12.     }
  13.    
  14. }
  15.  
  16.  
  17. resources.fileLoader[] = LIBRARY_PATH "/App/Regex_Functions.php"
  18. resources.fileLoader[] = LIBRARY_PATH "/App/Api_Functions.php"

Autoload своих библотек в Zend Framework 1.8+

Posted in Development, PHP, Tips And Tricks, ZendFramework on December 11th, 2009 by Yaroslav Vorozhko – Be the first to comment

Чтоб загружать в Zend Framework свои библиотеки, нам надо сделать следующее:
Первое - это добавить физический путь к библиотеке в include_path.
Второе - это указать префикс классов библиотеки, если такой вообще используется.

Добавить путь в include_path можно двумя способами:
1. Жетско прописать путь в public/index.php файле:

CODE:
  1. set_include_path(implode(PATH_SEPARATOR, array(
  2.     realpath(APPLICATION_PATH . '/../library'),
  3.     realpath(APPLICATION_PATH . '/../mylib'),
  4.     get_include_path(),
  5. )));

2. Прописать путь в конфигруационном файле application/configs/application.ini

CODE:
  1. includePaths.mylib = APPLICATION_PATH "/../mylib"

В обоих случаях мы добавляем путь к mylib в include_path. Второй способ более предпочтительный, так как на основе выбранной конфигурации (production, develeopment, test) можно устанавливать путь к различным версиям mylib.
Кстати используя этот же прием, можно устанавливать путь и к каталогу library/Zend и на основе конфигураций подгружать различный версии Zend Framework.

И так, второе что нам необходимо сделать - это подключить автозагрузчик и установить префикс используемый классами библиотеки.
Я прописал автозагрузчик в файле public/index.php

CODE:
  1. require_once 'Zend/Loader/Autoloader.php';
  2. $loader = Zend_Loader_Autoloader::getInstance();
  3. $loader->registerNamespace('My_');

В данном случае префикс классов в моей библиотеки "My_".

Также, этот же код можно прописать и в классе Bootstrap.php

CODE:
  1. protected function _initAutoload()
  2.     {
  3.         require_once 'Zend/Loader/Autoloader.php';
  4.         $loader = Zend_Loader_Autoloader::getInstance();
  5.         $loader->registerNamespace('My');
  6.     }

Все, теперь ZF знает как загружать классы из вашей бибилиотеки.

Пример использования Sphinx и Lucene на ZF для разбора почты

Posted in Development, PHP, Sphinx Search, ZendFramework on August 20th, 2009 by Yaroslav Vorozhko – Be the first to comment

Vikram Vaswani написал замечательный пост о том как используя Sphinx, Zend Framework и Lucene, создать поиск по почтовым сообщениям.

В статье рассказывается об основах использования Sphinx и Lucene, а также об основах разбора почтовых сообщений.  В качестве примера Vikram создает консольное приложение для индексации почты и для поиска по ней используя сначала Lucene, а потом и Sphinx.

В общем статья является хорошим примером как используя Sphinx и Lucene быстро сделать поисковик.

Если вы интересуетесь поисковыми движками, то наряду с Sphinx стоит обратить внимание на Solr.

Настраиваем Zend Application

Posted in Development, PHP, ZendFramework on August 13th, 2009 by Yaroslav Vorozhko – 2 Comments

С выходом Zend Framework 1.8 связано много новых изменений и дополнений. Самые значительные это добавление Zend_Application и Zend_Tool.

Zend_Tool представляет собой консольную программу управления проектами на Zend Framework.

Zend_Application это новая система загрузки приложения и конфигурирования проекта.

Рассмотрим как работать с Zend_Application подробнее.

Управление загрузкой приложения занимается Zend_Application_Bootstrap, он выполняет загрузку конфига, инициализацию компонентов, front контроллера, базы данных и объекта вида view.

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

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

Вы можете просто использовать copy-past приведенных скриптов, чтоб сэкономить время.

Давате создадим файловую структуру.

PHP:
  1. mkdir -p public/css
  2. mkdir -p public/img
  3. mkdir -p public/js
  4. mkdir -p application/configs
  5. mkdir -p application/controllers
  6. mkdir -p application/layouts/scripts
  7. mkdir -p application/models
  8. mkdir -p application/views/helpers
  9. mkdir -p application/views/scripts/index
  10. mkdir -p application/views/scripts/error
  11. mkdir -p data/session
  12. mkdir -p bin
  13. mkdir -p library/App
  14. mkdir -p tests/application
  15. mkdir -p tests/application/controllers

Теперь скачайте последний релиз ZF и скопируйте директорию Zend в library.

Public каталог

Создайте файл public/.htaccess

PHP:
  1. SetEnv APPLICATION_ENV development
  2.  
  3. RewriteEngine On
  4. RewriteCond %{REQUEST_FILENAME} -s [OR]
  5. RewriteCond %{REQUEST_FILENAME} -l [OR]
  6. RewriteCond %{REQUEST_FILENAME} -d
  7. RewriteRule ^.*$ - [NC,L]
  8. RewriteRule ^.*$ index.php [NC,L]

В файле public/index.php мы просто установим переменные окружения, а все остальное сделает Zend_Application. Как я упоминал раньше, большинство настроек хранится в конфиграционном файле.

public/index.php

PHP:
  1. <?php
  2. define('BASE_PATH', realpath(dirname(__FILE__) . '/../'));
  3. define('APPLICATION_PATH', BASE_PATH . '/application');
  4.  
  5. // Include path
  6.     BASE_PATH . '/library'
  7.     . PATH_SEPARATOR . get_include_path()
  8. );
  9.  
  10. // Define application environment
  11. defined('APPLICATION_ENV')
  12.     || define('APPLICATION_ENV',
  13.               (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV')
  14.                                          : 'production'));
  15.  
  16. // Zend_Application
  17. require_once 'Zend/Application.php';
  18.  
  19. $application = new Zend_Application(
  20.     APPLICATION_ENV,
  21.     APPLICATION_PATH . '/configs/application.ini'
  22. );
  23.  
  24. $application->bootstrap();
  25. $application->run();

Конфигурационный файл

application/configs/application.ini: В моем приложении используется 3 базы данных: основная база, база для разработки и база для тестирования, поэтому определение настроек баз данных разделено на 3 разных части.

PHP:
  1. [production]
  2.  
  3. # Debug output
  4. phpSettings.display_startup_errors = 0
  5. phpSettings.display_errors = 0
  6.  
  7. # Include path
  8. includePaths.library = APPLICATION_PATH "/../library"
  9.  
  10. # Bootstrap
  11. bootstrap.path = APPLICATION_PATH "/Bootstrap.php"
  12. bootstrap.class = "Bootstrap"
  13.  
  14. # Front Controller
  15. resources.frontController.controllerDirectory = APPLICATION_PATH "/controllers"
  16. resources.frontController.env = APPLICATION_ENV
  17.  
  18. # Layout
  19. resources.layout.layout = "layout"
  20. resources.layout.layoutPath = APPLICATION_PATH "/layouts/scripts"
  21.  
  22. # Views
  23. resources.view.encoding = "UTF-8"
  24. resources.view.basePath = APPLICATION_PATH "/views/"
  25.  
  26. # Database
  27. resources.db.adapter = "pdo_mysql"
  28. resources.db.params.host = "localhost"
  29. resources.db.params.username = "myproject"
  30. resources.db.params.password = "myproject"
  31. resources.db.params.dbname = "myproject_production"
  32. resources.db.isDefaultTableAdapter = true
  33.  
  34. # Session
  35. resources.session.save_path = APPLICATION_PATH "/../data/session"
  36. resources.session.remember_me_seconds = 864000
  37.  
  38. [testing : production]
  39.  
  40. # Debug output
  41. phpSettings.display_startup_errors = 1
  42. phpSettings.display_errors = 1
  43.  
  44. # Database
  45. resources.db.params.dbname = "myproject_testing"
  46.  
  47. [development : production]
  48.  
  49. # Debug output
  50. phpSettings.display_startup_errors = 1
  51. phpSettings.display_errors = 1
  52.  
  53. # Database
  54. resources.db.params.dbname = "myproject_development"

Загрузчик

application/Bootstrap.php: как определено в конфигурационном файле, приложение использует этот файл для процесса загрузки. Я предоставил Zend_Application выполнить всю инициализацию самостоятельно за исключение вида view. В view я хочу установить особый doctype XHTML.

PHP:
  1. <?php
  2. class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
  3. {
  4.     protected function _initView()
  5.     {
  6.         // Initialize view
  7.         $view = new Zend_View();
  8.         $view->doctype('XHTML1_STRICT');
  9.         $view->headTitle('My Project');
  10.         $view->env = APPLICATION_ENV;
  11.  
  12.         // Add it to the ViewRenderer
  13.         $viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper(
  14.             'ViewRenderer'
  15.         );
  16.         $viewRenderer->setView($view);
  17.  
  18.         // Return it, so that it can be stored by the bootstrap
  19.         return $view;
  20.     }
  21. }

Готово. Это и есть процесс загрузки. Ваше приложение теперь готово использовать ZF MVC и базу данных. Поэтому, давайте продолжим настроку специфических элементов приложения.

Добавим layout

Давайте добвим layout по умолчанию applicaiton/layouts/scripts/layout.phtml:

PHP:
  1. <?php echo $this->doctype() ?>
  2. <html>
  3. <head>
  4.     <?php echo $this->headTitle() ?>
  5.     <?php echo $this->headLink() ?>
  6.     <?php echo $this->headStyle() ?>
  7.     <?php echo $this->headScript() ?>
  8. </head>
  9. <body>
  10.     <?php echo $this->layout()->content ?>
  11. </body>
  12. </html>

Добавим контроллер и вид view

application/controllers/IndexController.php ничего особенного в нем:

PHP:
  1. <?php
  2. class IndexController extends Zend_Controller_Action
  3. {
  4.     public function indexAction()
  5.     {
  6.     }
  7. }

Дабавим view для index/index action в application/view/scripts/index/index.phtml

PHP:
  1. <h1 id="welcome-to-the-zend-framework">Welcome to the Zend Framework!</h1>

application/controllers/ErrorController.php вызывается в том случае, если запрашиваемый контроллер не был найден. В зависимости от переменных окружения он вызывает исключение и вывод трассировки стека.

application/controllers/ErrorController.php:

PHP:
  1. <?php
  2. class ErrorController extends Zend_Controller_Action
  3. {
  4.     public function errorAction()
  5.     {
  6.         $errors = $this->_getParam('error_handler');
  7.  
  8.         switch ($errors->type) {
  9.             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_CONTROLLER:
  10.             case Zend_Controller_Plugin_ErrorHandler::EXCEPTION_NO_ACTION:
  11.  
  12.                 // 404 error -- controller or action not found
  13.                 $this->getResponse()->setHttpResponseCode(404);
  14.                 $this->view->message = 'Page not found';
  15.                 break;
  16.             default:
  17.                 // application error
  18.                 $this->getResponse()->setHttpResponseCode(500);
  19.                 $this->view->message = 'Application error';
  20.                 break;
  21.         }
  22.  
  23.         $this->view->exception = $errors->exception;
  24.         $this->view->request   = $errors->request;
  25.     }
  26. }

И принадлежащий ему вид:

PHP:
  1. <h1 id="an-error-occurred">An error occurred</h1>
  2. <h3 id=""><?php echo $this->message ?></h3>
  3.  
  4. <? if ('development' == $this->env): ?>
  5.  
  6.     <h4 id="exception-information">Exception information:</h4>
  7.     <p>
  8.       <strong>Message:</strong> <?php echo $this->exception->getMessage(); ?>
  9.     </p>
  10.  
  11.     <h4 id="stack-trace">Stack trace:</h4>
  12.     <pre><?php echo $this->exception->getTraceAsString() ?></pre>
  13.  
  14.     <h4 id="request-parameters">Request Parameters:</h4>
  15.     <? var_dump($this->request->getParams()); ?>
  16.  
  17. <? endif; ?>

Теперь ваше приложение должно работать. Попробуйте открыть / и /foo. Вы должны будете увидеть index/index и error/error actions.

Сокращено и переведено из mafflog.

Прикручиваем свои сообщения к Zend Validate Email

Posted in Development, PHP, ZendFramework on August 11th, 2009 by Yaroslav Vorozhko – Be the first to comment

Валидацией email адресов в ZF занимается Zend_Validate_Email. Кто не знает, email состоит из двух частей, имени и хоста. Хост проверяется с помощью Zend_Validate_Hostname и все эти вещи выполняются в background, т.е. мы не получем каких либо нотификаций о происходящих там процессах.

Так, вот Thomas Weidner разобрался с этой проблемой и предлагает свое решение валидиции email.

Zend Mail как вложить изображение в письмо

Posted in Tips And Tricks, ZendFramework on August 11th, 2009 by Yaroslav Vorozhko – Be the first to comment

Есть два варианта добавить картинку в почтовое html сообщение.
1. Использовать удаленный сервер для загрузки сообщения.
2. Вложить сообщение в письмо и ссылаться на него в html документе.
Первый способ очень простой и не требует программирования:

PHP:
  1. <img src="http://somededicateserver.com/images/logo.gif" />

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

PHP:
  1. $html = $this->_request->getParam('html','');//в html у нас храниться исходный HTML код сообщения
  2. $mail = new Zend_Mail('UTF-8');
  3. //убедитесь, что файл существует и доступен для чтения
  4. $filename = '/path/htdocs/img/logo.gif';
  5. if (is_readable($filename)) {
  6.   $mail->setType(Zend_Mime::MULTIPART_RELATED);   
  7.   $at = $mail->createAttachment(file_get_contents($filename))
  8.   $at->type = 'image/gif'
  9.   $at->disposition = Zend_Mime::DISPOSITION_INLINE
  10.   $at->encoding = Zend_Mime::ENCODING_BASE64
  11.   $at->id = 'cid_' . md5_file($filename);
  12.   $html = str_replace('file://attached_image''cid:' . $at->id$html);   
  13. }
  14. $mail->setBodyHtml($html, 'UTF-8', Zend_Mime::ENCODING_8BIT);

Внутри html сообщения у нас есть специальная строка (file://attached_image), ссылка на изображение:

PHP:
  1. <img src="file://attached_image" />

которая, после обработки, будет заменена на вложенное в письмо изображение, и будет иметь следующий вид:

PHP:
  1. <img src="cid:cid_4b3fdb60e9422ce97926cc8d3b601188" />

Все, отправляем письмо и проверяем результат.