Sie sind auf Seite 1von 6

Build your own CMS with ZF2

Zend Framework 2 tutorial provided by

Copyright User: thomas Online version:


I already wrote once a tutorial how to create your own CMS functionallity with the Zend Framework. The Zend Framework has a lot of changes so this is out-dated and I researched how to realize a new CMS controller. Here is it!

1. Working Zend Framework 2 application (see 2. A concept of working with models. If you don't know how to load date from a database, read the tutorial here (see

Database table
Create a table for the pages in your mySQL database. Run this query against your database.
CREATE TABLE page( id int(11) NOT NULL auto_increment, identifier varchar(255) NOT NULL, title varchar(255) NOT NULL, content text NOT NULL, PRIMARY KEY (id) );

For testing we need data. I give you one data for the page 'imprint'. Run this query against your database.
INSERT INTO `page` (`id`, `identifier`, `title`, `content`) VALUES (NULL, 'imprint', 'Imprint', '<br/>Anystreet 5<br/>');

Application config
Open your application's config file (/config/application.config.php) and add 'Page' to your modules.
<?php return array( 'modules' => array( 'Application', 'Page', // add this ), 'module_listener_options' => array( 'config_glob_paths' => array( 'config/autoload/{,*.}{global,local}.php', ), 'module_paths' => array( './module', './vendor', ), ), );

Maybe you have already a few modules. Just add 'Page' under them.


Create module path

/Page /config /src /Page /Controller /Model

Moduel config file

Create the file module.config.php in /module/Page/config with the following content:
<?php return array( 'controllers' => array( 'invokables' => array( 'Page\Controller\Page' => 'Page\Controller\PageController', ), ), 'router' => array( 'routes' => array( 'page' => array( 'type' => 'segment', 'options' => array( 'route' => '/page[/:action][/:id]', 'constraints' => array( 'action' => '[a-zA-Z][a-zA-Z0-9_-]*', 'id' => '[0-9]+', ), 'defaults' => array( 'controller' => 'Page\Controller\Page', 'action' => 'index', ), ), ), ), ), );

This gives your application information about routing and controllers and views.

Module file
Create the file Module.php in /module/Page with the following content:
<?php namespace Page; use Page\Model\Page; use Page\Model\PageTable; use Zend\Db\ResultSet\ResultSet; use Zend\Db\TableGateway\TableGateway; class Module { public function getAutoloaderConfig() { return array( 'Zend\Loader\ClassMapAutoloader' => array( __DIR__ . '/autoload_classmap.php', ), 'Zend\Loader\StandardAutoloader' => array( 'namespaces' => array( __NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__, ), ), ); } public function getConfig() { return include __DIR__ . '/config/module.config.php';

} public function getServiceConfig() { return array( 'factories' => array( 'Page\Model\PageTable' => function($sm) { $tableGateway = $sm->get('PageTableGateway'); $table = new PageTable($tableGateway); return $table; }, 'PageTableGateway' => function ($sm) { $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter'); $resultSetPrototype = new ResultSet(); $resultSetPrototype->setArrayObjectPrototype(new Page()); return new TableGateway('page', $dbAdapter, null, $resultSetPrototype); }, ), ); } }

This code sets the autoloader config, namespaces, it tell's the application where the module.config.php is and in getServiceConfig() are our two models which we later will create.

Autoload classmap
Create the file autoload_classmap.php in /module/Page with the following content:
<?php return array();

Ok here you have to create a model as you always do it. If you have no concept you can read our tutorial ( about generic models. I write the code now for our way here to create models.

Create the file Page.php in /module/Page/src/Page/Model with the following content:
<?php namespace Page\Model; use Object\Model\Object; class Page extends Object { }

It extends the generic class and get's all functionallity by doing this.

Create the file PageTable.php in /module/Page/src/Page/Model with the following content:
<?php namespace Page\Model; use Object\Model\ObjectTable; class PageTable extends ObjectTable { public function getPage($id) { return parent::getObject($id); } public function getPageByIdentifier($identifier)

{ $rowset = $this->_tableGateway->select(array('identifier' => $identifier)); $row = $rowset->current(); if (!$row) { throw new \Exception("Could not find row $identifier"); } return $row; } public function savePage(Page $page) { return parent::saveObject($page); } public function deletePage($id) { return parent::deleteObject($id); } }

Ok this is acutally always the same. This class provides all features for loading, deleting and saving pages. But it also has a important function which we later need to get a page by it's identifier (getPageByIdentifier()). All other functions just pass the params to the parent functions. If you want to know more about that, read the tutorial about generic models on our page.

Now comes the most important and interesting part. Create the file PageController.php in /module/Page/src/Page/Controller with the following content:
<?php namespace Page\Controller; use Zend\Mvc\Controller\AbstractActionController; use Page\Model\Page; class PageController extends AbstractActionController { /** * PageTable * @var Page\Model\PageTable */ protected $_pageTable; /** * Get PageTable object * @return Page\Model\PageTable */ public function getPageTable() { if (!$this->_pageTable) { $sm = $this->getServiceLocator(); $this->_pageTable = $sm->get('Page\Model\PageTable'); } return $this->_pageTable; } /** * We are overwriting the dispatch function so that all requests to this controller are catched here. * We use the action as the identifier, so that our calls will be * By the identifier we get the page. * * @param \Zend\Stdlib\RequestInterface $request * @param \Zend\Stdlib\ResponseInterface $response * @return type * @throws \Page\Controller\Exception */ public function dispatch(\Zend\Stdlib\RequestInterface $request, \Zend\Stdlib\ResponseInterface $response = null) { $identifier = (string)$this->getEvent()->getRouteMatch()->getParam('action'); $pageTable = $this->getPageTable(); try { $page = $pageTable->getPageByIdentifier($identifier); // get the renderer to manipulate the title $renderer = $this->getServiceLocator()->get('Zend\View\Renderer\PhpRenderer'); // set the page title in the html head $renderer->headTitle($page->getTitle());

// write the models content to the websites content $this->layout()->content = '<h1>' . $page->getTitle() . '</h1>' . $page->getContent(); } catch(\Exception $ex) { // if we are on development, show the exception, // if not (we are in production) show the 404 page if($_SERVER['APPLICATION_ENV'] == 'development') { throw $ex; } else { // it is necessery to call the parent dispatch, otherwise the notFoundFunction doesn't work. parent::dispatch($request, $response); $this->notFoundAction(); return; } } } }

Most of the logic is described in the code comments above. What I do is, I overwrite the dispatch function so that I catch every call on the controller. I use the action as the identifier. So every call (e.g. is routed to this function. I get the action name, in the example it is 'imprint' and use it as the identifier. Then I try to get a page with this identifier. If I find any page, I write the information to the head title and content. If not, I show a 404 on production and throw the exception on development environment. That's all. Now you need a administration interface where you can manage your pages and you have the basic functionallity for a CMS in Zend Framework 2.

On the beginning we inserted data for a page with the identifier 'imprint'. Call now.

You should see a imprint. If you call any other page you should get a 404 or an exception, depending if you are on development environment or not.

You can download the source here: Extract it in your module folder and don't forget to add 'Page' to your /config/application.config.php so that Zend knows about the new module and to create the table user in your database as described on the beginning of the tutorial.