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

Идея весьма проста — в админке большинство контроллеров показывают списки разных объектов и редактируют их. Поэтому всё, что нужно знать такому контроллеру — откуда брать данные, как построить запрос для разбивки на страницы и в какой форме всё это редактировать.

Класс контроллера:

abstract
class Controller_Backend_ListingAbstract extends Zend_Controller_Action
{
	protected $_page_size = 15;

	abstract protected function getTable();
	abstract protected function getEditForm();
	abstract protected function getPaginatorQuery($request);

	public function indexAction()
	{
		$request = $this->getRequest();

		$this->view->paginator = Zend_Paginator::factory($this->getPaginatorQuery($request));
		$this->view->paginator->setCurrentPageNumber(intval($request->get('page')));
		$this->view->paginator->setItemCountPerPage($this->_page_size);
	}

	public function addAction()
	{
		$form = $this->getEditForm();
		if ($form == null)
			$this->_helper->redirector('index');

		$form->getElement('id')->setValue(-1);

		$this->view->form = $form;

		return $this->render('edit');
	}

	public function editAction()
	{
		$rq = $this->getRequest();

		$form = $this->getEditForm();
		if ($form == null)
			$this->_helper->redirector('index');

		$table = $this->getTable();

		if ($rq->isPost())
		{
			if ($form->isValid($rq->getPost()))
			{
				$values = $form->getValues();

				if ($values['id'] == -1)
				{
					$row = $table->createRow();
					unset($values['id']);
				}
				else
				{
					$row = $table->fetchById($values['id']);
					if ($row == null)
					{
						$this->_helper->redirector('index');
					}
				}

				$row->setFromArray($values);
				$row->save();

				$this->_helper->redirector('index');
			}
		}
		else
		{
			$row = $table->fetchById($rq->get('id'));
			if ($row == null)
			{
				$this->_helper->redirector('index');
			}

			$form->populate($row);
		}

		$this->view->object = $row;
		$this->view->form = $form;
	}

	public function deleteAction()
	{
		$rq = $this->getRequest();

		$table = $this->getTable();
		$row = $table->fetchById($rq->get('id'));
		if ($row != null)
		{
			$row->delete();
		}

		return $this->_helper->redirector('index');
	}

	public function viewAction()
	{
		$rq = $this->getRequest();

		$table = $this->getTable();
		$row = $table->fetchById($rq->get('id'));
		if ($row == null)
		{
			return $this->_helper->redirector('index');
		}

		$this->view->object = $row;
	}
}

Чтобы всё работало нужно:

  • у всех объектов должен быть PRIMARY INDEX id;
  • в классе таблицы нужно определить метод fetchById ($id).
Отображение, конечно же, делается во вьюшках.

Применение этого контроллера весьма незамысловато:

class JobsController extends Controller_Backend_ListingAbstract
{
	protected function getEditForm()
	{
	}

	protected function getPaginatorQuery($request)
	{
		$table = $this->getTable();
		return $table->select();
	}
	protected function getTable()
	{
		return new JobsTable();
	}
}

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

Для сохранения сложных объектов нужно переопределить метод setFromArray у класса строки и метод populate у формы.

Zend Framework: абстрактный контроллер для админки
Метки: