Архив рубрики: Zend Framework

Zend Framework: объединение кнопок в форме в одну линию в Zend_Form

Задача: объединить, сгенерированные Zend_Form, кнопки «Обновить» и «Удалить», так чтобы они располагались на одной линии.

Решение: использование декораторов и DisplayGroup.

		$this->addElement (new Zend_Form_Element_Submit('submit', array(
            	'label'	=> 'Обновить',
        		'class'	=>	'ui-state-default ui-corner-all ui-button',
				'decorators'	=>	array('ViewHelper')
		  	))
		);

        $this->addElement (new Zend_Form_Element_Button('delete', array(
            	'label'	=> 'Удалить',
        		'id'	=>	'delete-button',
        		'class'	=>	'ui-state-default ui-corner-all ui-button',
        		'decorators'	=>	array('ViewHelper')
        	))
        );

       $this->addDisplayGroup(array('submit', 'delete'), 'submitButtons', array(
	        'decorators' => array(
	            'FormElements',
	            array('HtmlTag', array('tag' => 'div', 'class' => 'form-buttons')),
	        ),
	   ));

Здесь $this — это потомок класса Zend_Form, т.е. class Application_Model_Form_User extends Zend_Form.
Получится что-то типа такого:

Пример интерфейса с кнопками в одну линию в Zend_Form

Пример интерфейса с кнопками в одну линию в Zend_Form

Как это работает

В объявлении каждого элемента мы оставляем только один декоратор, который выводит только сам элемент. Эти элементы без декораторов мы добавляем в одну визуальную группу на основе div и для возможности стилизации в CSS добавляем группе класс «form-buttons».

Zend Framework: пример помощников вида для интеграции ElRTE и ElFinder

Задача: унифицировать и упростить задачу инициализации текстового редактора ElRTE и файлового менеджера ElFinder.

Решение: использование специально для этого придуманных помощников вида (view helpers) в ZF.

Я использую ElRTE и ElFinder в административной панели сайта. Это наиболее удобные инструменты для визуального редактирования html-контента, а также для работы с файлами на серверами. Посему пример будет для модуля admin. Впрочем, сменив название модуля на Application, пример прекрасно подойдет для модуля по умолчанию (тот который в основной папке «/application/»).

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

  1. Создаем модульное приложение на ZF с модулем «admin». Подробнее об этом можете прочитать в одной из предыдущих моих записях.
  2. Скачиваем и сохраняем в «/public/js/» ElRTE и ElFinder
  3. Настраиваем коннектор для ElFinder
  4. Создаем файл «/application/modules/admin/view/helpers/EnableElRTE.php» со следующим содержимым:
    <?php
    /**
     * Class inserts neccery code for initialize rich text editor ElRTE
     */
    class Admin_View_Helper_EnableElRTE extends Zend_View_Helper_Abstract{
    
    	public function enableElRTE() {
    		$elrte_base_uri = "/js/back-end/elrte-1.0rc4/";
    
    		$this->view->headLink()->appendStylesheet("{$elrte_base_uri}css/elrte.full.css");
    		$this->view->headScript()->appendFile("{$elrte_base_uri}js/elrte.min.js");
    		$this->view->headScript()->appendFile("{$elrte_base_uri}js/i18n/elrte.ru.js");
       	}
    }
    
  5. Создаем файл «/application/modules/admin/view/helpers/EnableElFinder.php»:
    <?php
    /**
     * Class inserts neccery code for initialize file manager ElFinder
     *
     * @author Dimitry Dushkin
     *
     */
    class Admin_View_Helper_EnableElFinder extends Zend_View_Helper_Abstract{
    
    	public function enableElFinder() {
    		$elfinder_base_uri = "/js/back-end/elfinder-1.1/";
    
    		$this->view->headLink()->appendStylesheet("{$elfinder_base_uri}css/elfinder.css");
    		$this->view->headScript()->appendFile("{$elfinder_base_uri}js/elfinder.min.js");
    
    		$this->view->headScript()->captureStart() ?>
    			var opts = {
    				lang : 'ru',
    				styleWithCss : false,
    				width	: 800,
    				height  : 200,
    				toolbar : 'normal',
    				fmAllow  : true,
    				fmOpen   : function(callback) {
    					$('<div id="myelfinder" />').elfinder({
    					   	url : '<? echo $elfinder_base_uri?>connectors/php/connector.php',
    						lang : 'ru',
    						dialog : { width : 900, modal : true, title : 'Файлы' }, // открываем в диалоговом окне
    						closeOnEditorCallback : true, // закрываем после выбора файла
    						editorCallback : callback
    		            })
    	       		}
    	        };
           	<?php $this->view->headScript()->captureEnd();
       	}
    }
    
  6. В представлении IndexAction IndexController’a модуля admin (по умолчанию такие штуки располагаются в «/application/modules/admin/view/scripts/index/index.phtml») пишем следующее:
    
    <? echo $this->enableElRTE();?>
    <? echo $this->enableElFinder();?>
    
    <script type="text/javascript">
         $().ready(function() {
              // создаем редактор
              $('.rte_textarea').elrte(opts);
         });
    </script>
    <form method="get">
         <textarea name="content" id="content" class="rte_textarea" rows="5" cols="45"></textarea>
    </form>
    
  7. В основном шаблоне («/application/layouts/scripts/index.phtml») при этом должно быть что-то типа такого (стандартный код для шаблонов ZF):
    <?php echo $this->doctype() ?>
    <html xmlns="http://www.w3.org/1999/xhtml">
    <head>
    	<?php echo $this->headTitle() ?>
    	<?php echo $this->headMeta() ?>
    	<?php echo $this->headLink() ?>
    	<?php echo $this->headScript() ?>
    </head>
    <body>
             <?php echo $this->layout()->content ?>
    </body>
    </html>
    
  8. Удостоверяемся, что все работает как надо, пройдя по ссылке типа http://localhost/admin/index/index

Получим что-то типа такого

семейное фото ElRTE и ElFinder

семейное фото ElRTE и ElFinder

Как это работает

Помощники вида необходимы для динамического добавления необходимых элементов в выходной html-код. Как видно, каждый наш помощник является потомком класса Zend_View_Helper_Abstract, который реализует интерфейс, позволяющий получить доступ к глобальному объекту Zend_View, который как раз и отвечает за выходной html-код.

В каждом помощнике мы обращаемся к стандартным помощникам вида (HeadScript Helper для добавления js-файлов и js-кода и HeadStyle Helper для добавления файлов стиля) через глобальный объект Zend_View.

Ссылки в записи

 

UPDATE: по твиттеру товарищ Вредный рассказал о своём усовершенствованном решении этого вопроса. Там предлагается подключать elRte и elFinder в описании формы.

Zend Framework: включение модульной архитектуры

К сожалению, не все рутинные задачи доступны с помощью Zend_Tool. Одна из таких задач — включение механизма модульной архитектуры, что на самом деле немного удивительно, т.к. команда на создание модуля со структурой по умолчанию существует.

Путь создания приложения с нуля с помощью Zend_Tool довольно прост:

  1. Удостоверяемся, что есть доступ к zf.sh (для Linux) или zf.bat (для Windows);
  2. Заходим в директорию, в которой хотим создать приложение, например так
    cd /home/user/data/www/example.ru/
    
  3. Cоздаем проект Zend Framework:
     zf create project example
     
  4. Включаем поддержку шаблонов (layout):
     zf enable layout
     
  5. Создаем, например, модуль video:
     zf create module video
     
  6. Создаем для него Index контроллер с действием IndexAction:
     zf create controller Index index-action-included video
     
  7. В файле /application/config/application.ini включаем поддержку модулей, вписав после тега [production] следующее:

    resources.frontController.moduleDirectory = APPLICATION_PATH "/modules"
    resources.modules[] =
  8. Для включения автозагрузки классов модуля (моделей или форм, например) в корне папки модуля (/application/modules/video/) создаем файл Bootstrap.php со следующим содержимым:
    <?php class Video_Bootstrap extends Zend_Application_Module_Bootstrap {}

Вот и всё, все дело в последнем шаге. К сожалению, без него стандартные правила направления запросов к модулю не работают, то есть запрос типа:

example.ru/video/index/index

вызовет ошибку, хотя должен был вызвать IndexAction в IndexController в модуле video.
Строка «resources.modules[] =» включает автозагрузку классов для модулей.

Созданное в записи приложение с моим небольшим изменением для показа времени выполнения скриптов можно скачать по этой ссылке.

Ссылки в записи

Zend Framework: пример реализации поиска с помощью Zend_Search_Lucene

Задача: организовать полноценный, быстрый и релевантный поиск по сайту.

Решение: использовать php-имплементацию поискового движка «Люсин», или по-нашему Java Lucene, — Zend_Search_Lucene. Этот вариант хорош тем, что запросто заведется даже на виртуальном хостинге, где нет возможности ставить свои приложения на сервер.

Конечно, можно решить эту задачу и с помощью Sphinx, но зачем, если мы все так привыкли к инструментам Zend Framework?) К тому же во многих тестах решение на php работает не сильно медленней sphinx. Есть еще вариант: реализовать поиск силами SQL, но в этом случае при больших размерах баз данных и небольшом объеме оперативной памяти, выделенном процессу mysqld, мы рискуем напороться на медленную скорость прохождения запросов.

1. Настраиваем приложение

Начнем с создания простой среды для работы приложения. Здесь всё стандартно, стоит просто вспомнить оригинальный Zend Framework Quick Start или еще какой-нибудь мануал. Теперь добавим наш модуль, который будет отвечать за поиск. Здесь тоже всё стандартно, не забудем также положить файл Bootstrap.php в корень модуля. Это необходимо для работы системы автозагрузки классов. У файла /application/modules/search/Bootstrap.php следующее содержимое:

<?php
class Search_Bootstrap extends Zend_Application_Module_Bootstrap
{

}

В итоге получаем такую структуру приложения:

2. Создаем поисковой индекс

В основе у нас будет простая таблица со словами:

CREATE TABLE IF NOT EXISTS `ru_words` (
  `id` int(11) NOT NULL auto_increment,
  `name` varchar(50) NOT NULL,
  PRIMARY KEY  (`id`),
) DEFAULT CHARSET=utf8;

INSERT INTO `ru_words` (`id`, `name` ) VALUES
(1, 'абрикос'),
(2, 'египет'),
(3, 'абзац'),
(4, 'зенд');

Создадим файл /application/modules/search/models/Search.php:

<?php
class Search_Model_Search extends Zend_Db_Table_Abstract {

	protected $_searchIndexPath;	//путь для папки с файлами поискового индекса
	protected $_name = 'ru_words';	//имя таблицы в БД, для которой создаем поисковой индекс

	public function __construct() {
		$this->_searchIndexPath = APPLICATION_PATH . '/data/search-index';
		set_time_limit(900);
		Zend_Search_Lucene_Analysis_Analyzer::setDefault(
			new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());

	}

	/**
	 * Создает новый поисковой индекс
	 */
	public function updateIndex() {
		//удаляем существующий индекс, в большинстве случае эта операция с последующий созданием нового индекса работает гораздо быстрее
		$this->recursive_remove_directory($this->_searchIndexPath, TRUE);

	  	try {
	  		$index = Zend_Search_Lucene::create($this->_searchIndexPath);
	  	} catch (Zend_Search_Lucene_Exception $e) {
	  	 echo "<p class=\"ui-bad-message\">Не удалось создать поисковой индекс: {$e->getMessage()}</p>";
	  	}

		try {
			//выбираем все слова из БД
			$words = $this->fetchAll($this->select());
			$i = 0;
			foreach ($words as $w) {
				$doc = new Zend_Search_Lucene_Document();
				$doc->addField(Zend_Search_Lucene_Field::Keyword('word_id', $w['id']));
				$doc->addField(Zend_Search_Lucene_Field::Text('name', $w['name'], 'UTF-8'));
				$index->addDocument($doc);
				$i++;
			}
		} catch (Zend_Search_Lucene_Exception $e) {
    		echo "<p class=\"ui-bad-message\">Ошибки индексации: {$e->getMessage()}</p>";
    	}

    	//let's clean up some
    	$index->optimize();

    	echo "<p class=\"ui-good-message\">
    			Поисковой индекс слов заново создан. Слов добавлено: {$i}. <br />
    			Индекс оптимизирован.</p>";
	}

	/**
	 * recursive_remove_directory( directory to delete, empty )
	 * expects path to directory and optional TRUE / FALSE to empty
	 *
	 * @param $directory
	 * @param $empty TRUE - just empty directory
	 */
	function recursive_remove_directory($directory, $empty=FALSE)
	{
		if(substr($directory,-1) == '/')
		{
			$directory = substr($directory,0,-1);
		}
		if(!file_exists($directory) || !is_dir($directory))
		{
			return FALSE;
		}elseif(is_readable($directory))
		{
			$handle = opendir($directory);
			while (FALSE !== ($item = readdir($handle)))
			{
				if($item != '.' && $item != '..')
				{
					$path = $directory.'/'.$item;
					if(is_dir($path))
					{
						$this->recursive_remove_directory($path);
					}else{
						unlink($path);
					}
				}
			}
			closedir($handle);
			if($empty == FALSE)
			{
				if(!rmdir($directory))
				{
					return FALSE;
				}
			}
		}
		return TRUE;
	}
}

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

Стоит отметить решение с удалением предыдущего индекса. Создание нового индекса для 2500 записей занимает 40-60 секунд, если же использовать алгоритмы обновления индекса, то такая операция займет 8-10 минут.

Теперь создадим файл /application/modules/search/controllers/IndexController.php:

<?php

class Search_IndexController extends Zend_Controller_Action {

	public function updateIndexAction() {
		$this->_helper->layout()->disableLayout();
		$this->_helper->viewRenderer->setNoRender(true);

		$model = new Search_Model_Search();
		$model->updateIndex();
	}
}

Здесь мы просто создаем action для вызова функции создания поискового индекса. Обратиться к ней мы всегда с можем по адресу http://localhost/search/index/update-index

3. Осуществляем поиск

Добавим нашей модели (/application/modules/search/models/Search.php) функцию поиска:

	/**
	 * Search by query
	 *
	 * @param $query search query
	 * @return array Zend_Search_Lucene_Search_QueryHit
	 */
	public function search($query) {
		try{
			$index = Zend_Search_Lucene::open($this->_searchIndexPath.'/words');
		} catch (Zend_Search_Lucene_Exception $e) {
			echo "Ошибка:{$e->getMessage()}";
		}

		$userQuery = Zend_Search_Lucene_Search_QueryParser::parse($query);

		return $index->find($userQuery);
	}

Теперь добавим её вызов в соответствующем котроллере ( /application/modules/search/controllers/IndexController.php):

	public function searchAction() {
		$model = new Search_Model_Search();
		$this->view->query = $this->_getParam('query');
		$this->view->hits = $model->search($this->view->query);
	}

И соответствующий вид по адресу /application/modeuls/view/scripts/search.phtml:

<?php

if (empty($this->hits)){
	echo "Ничего не найдено.";
} else {
	echo "<ul>";
	foreach($this->hits as $hit){
		echo "<li>{$hit->name}</li>";
	}
	echo "</ul>";
}

4. Смотрим, как работает

Заходим по ссылке http://localhost/search/index/search/?query=зенд и видим, что у нас есть в индексе на этот счет.

Вот и сказу конец. Как видно, всё довольно прозрачно, просто стоит потратить время на официальный мануал для компонента (он, кстати, есть на русском, но английском он полнее).

В конце приведу цифры сравнения простого поиска с помощью SQL и Zend_Search_Lucene. В таблице с 2500 записями, в каждой из которых по 6 полей, поиск с SQL занимает 130-350 мс (такой разброс во времени обуславливается кешированием запросов) на VPS с 400 МГц и 256 ОЗУ. На той же конфигурации запросы через Zend_Search_Lucene занимают 145-200 мс. Такие сравнения, конечно, не показатель для больших проектов, но дают представления об общей картине в рамках средних и небольших проектов.

Скачать архив с тестовым приложением

<?php
class Search_Model_Search extends Zend_Db_Table_Abstract { 

protected $_searchIndexPath;    //path to initial data folder
protected $_name = ‘ru_words’;                //database adapter

public function __construct() {
$this->_searchIndexPath = APPLICATION_PATH . ‘/data/search-index’;
set_time_limit(900);
Zend_Search_Lucene_Analysis_Analyzer::setDefault(
new Zend_Search_Lucene_Analysis_Analyzer_Common_Utf8_CaseInsensitive());

}

/**
* Создает новый поисковой индекс
*/
public function updateIndex() {
//удаляем существующий индекс, в большинстве случае эта операция с последующий созданием нового индекса работает гораздо быстрее
$this->recursive_remove_directory($searchIndexPath, TRUE);

try {
$index = Zend_Search_Lucene::create($searchIndexPath);
} catch (Zend_Search_Lucene_Exception $e) {
echo «<p class=\»ui-bad-message\»>Не удалось создать поисковой индекс: {$e->getMessage()}</p>»;
}

try {
//выбираем все слова из БД
$words = $this->fetchAll($this->select());

Zend Framework: модульное тестирование с помощью Zend_Test и PHPUnit

Задачи:

  1. Изучить основы TDD — test-driven development — разработка через тестирование
  2. Воспользоваться на практике TDD в приложении, построенном на Zend Framework, с помощью Zend_Test и PHPUnit

Решение:

Первая задача, решается довольно просто — читаем соответствующую литературу. Мне в этом сильно помог перевод статьи Томаса и Ханта «Учимся любить юнит-тестирование».

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

Юнит-тестирование силами Zend_Test и PHPUnit

Сначала необходимо поставить сам фреймворк PHPUnit. Он входит в состав пакетов PEAR, поэтому сначала необходимо будет поставить сам PEAR. В debian системах делается это так:

apt-get install php-pear

Далее действуем по довольно короткому мануалу с сайта PHPUnit.

Далее, если вы создавали Zend Framework проект с помощью командной строки, то могли обнаружить следующую, казалось бы, лишнюю структуру папок и файлов:

screen-test-folders

Эти файлы пригодятся нам для тестов.

Первым делом заполняем файл phpunit.xml — конфигурационный файл для PHPUnit. Я почти полностью взял его из этой статьи:

<?xml version="1.0" encoding="UTF-8" ?>
<phpunit bootstrap="./application/bootstrap.php"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
stopOnFailure="true"
syntaxCheck="true">

    <!-- запускаем все тесты из корневой директории -->
    <testsuite name="Main Test Suite">
        <directory>./</directory>
    </testsuite>

    <filter>
    <!-- не смотрим на следующие директории -->
        <blacklist>
            <directory suffix=".php">/usr/share/php</directory>
            <directory suffix=".php">../tests</directory>
        </blacklist>
       <!-- смотрим лишь на следующие директории -->
       <whitelist>
           <directory suffix=".php">../application</directory>
                <exclude>
                      <directory suffix=".phtml">../application</directory>
                       <file>../application/Bootstrap.php</file>
                </exclude>
        </whitelist>
    </filter>
    <logging>
         <!-- логирование и создание отчета -->
         <log type="coverage-html" target="./log" charset="UTF-8" yui="true" highlight="true" lowUpperBound="35" highLowerBound="70"/>
    </logging>
</phpunit>

Далее, в файл /test/application/bootstrap.php практически полностью копируем оригинальный index.php из основного приложения:

<?php
error_reporting(E_ALL | E_STRICT);
// Define path to application directory
defined('APPLICATION_PATH')
|| define('APPLICATION_PATH', realpath(dirname(__FILE__) . '/../../application'));

// Define application environment
defined('APPLICATION_ENV')
|| define('APPLICATION_ENV', (getenv('APPLICATION_ENV') ? getenv('APPLICATION_ENV') : 'production'));

// Ensure library/ is on include_path
set_include_path(realpath('/var/www/libraries/ZF-1.9.7/library') . PATH_SEPARATOR
. get_include_path());

require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();

require_once 'ControllerTestCase.php';

Как видно, в конце мы включаем файл, которого еще нет. Исправим оплошность и создадим файл /tests/application/ControllerTestCase.php:

<?php

abstract class ControllerTestCase extends Zend_Test_PHPUnit_ControllerTestCase
{

    public function setUp() {
         // Assign and instantiate in one step:
         $this->bootstrap = new Zend_Application(
                                  APPLICATION_ENV,
                                  APPLICATION_PATH . '/configs/application.ini'
                            );
         parent::setUp();
     }
}

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

Ну и последнее, сам тест. Создадим папку и файл /test/application/controllers/IndexControllerTest.php.  Рекомендую придерживаться оригинальной структуры приложения, чтобы в будущем, когда будет много тестов, не происходило путаницы с их месторасположением. Содержимое нашего файла с тестами:

<?php
class IndexControllerTest extends ControllerTestCase {
      public function testTestAction() {
           # "Идем" в корень сайта
           $this->dispatch('/');
           # Проверяем, стоит ли у нас IndexController?
           $this->assertController('index');
           # Проверяем, запущенно ли indexAction?
           $this->assertAction('index');
      }
}

И, соответственно, долгожданный запуск первого теста. Для этого в консоли необходимо попасть в папку /tests/ и выполнить команду phpunit. Автоматически подхватится файл конфигурации phpunit.xml и пойдут тесты. Если мы ничего не напутали раньше, то в консоли должен получиться примерно такой результат:


PHPUnit 3.4.10 by Sebastian Bergmann.
Time: 0 seconds, Memory: 11.25Mb
OK (1 test, 2 assertion)

Поздравляю, самое сложно позади.) Осталось только разобраться, какие есть методы для тестирования и как ими пользоваться. Перечислять их всех и проводить по каждому тест — дело, очевидно, неблагодарное.) Поэтому скажу лишь, что суть (или как написали в мануале, «сердце») юнит-тестирования в запуске функции с определенными параметрами, при этом с указанием ожидаемого результата. Если ожидания сошлись с действительностью — OK, а вот если нет — поздравляю, вы не зря писали тест!)

Actionscript + Zend_AMF: вынимаем данные из объекта для отправки

Задача: создать на основе «навороченного» объекта  простой объект с данными.

Решение:

var tmp:Object = new Object();
// Prepare data to send
for (var key:String in sendData) {
      tmp[key] = sendData[key];
}

А теперь небольшая предыстория с комментариями 🙂

Пользуясь рекомендациями Adobe по работе с формами в Flex 4 сделал в форме так называемый Data Model с помощью <fx:model>.

<fx:Model id="sendData">
    <data>
        <sportsman_id>{sportsmanId}</sportsman_id>
        <uf_sd>{uf_sd.text}</uf_sd>
        <uf_dd>{uf_dd.text}</uf_dd>
     </data>
</fx:Model>

Вроде и удобно, и наглядно вышло, только вот, если скормить удаленному объекту (RemoteObject) такой объект с данными, то ничего не будет принято на принимающей стороне с Zend_AMF, видимо не происходит автоматической фильтрации данных.

Конечно, проблему можно было решить простым созданием нового объекта с поочередным присваиванием свойств объекта, но тогда какой профит от заморочек с Data Model?) Вот и я подумал, что профита не будет, но штука действительно удобная, поэтому немного пораскинув мозгами написал простой код конвертации, который вы сможете увидеть в начале заметки.

Zend Framework не в корне сайта

Небольшой tip.

Если необходимо развернуть приложение на Zend Framework в отличной от корня сайта папке (например, «http://anysite.ru/zf-application/«), то на этот случай у FrontController есть замечательный метод — setBaseUrl. Для нашего примера BootStrap.php будет следующий:

<?php

class Bootstrap extends Zend_Application_Bootstrap_Bootstrap
{
   /**
    * Bootstrap the Router
    *
    * @return void
    */
    protected function _initRouter()
    {
       	// Load frontController if it haven't been already loaded
		$this->bootstrap('FrontController');
    	$front = $this->getResource('FrontController');
    	$front->setBaseUrl('/zf-application/');
    }
}