LEVEL UP!
Migrating your ZF1 app to ZF2
Gary Hockin
@GeeH on Twitter
GeeH on IRC (Freenode #zftalk)
ZF1 and ZF2 Contributor
ZF2 Docs Maintainer
Yolo Certified Engineer
Roave Team Member
The App
The App
Why?
How?
Strangler
http://www.moviepostershop.com/the-brighton-strangler-movie-poster-1945
BIG BANG!
http://www.amazon.co.uk/Big-Bang-Theory-Season-Complete/dp/B0028BAWU2
You do have service layers, right???
Installing ZF2
composer.phar create-project -sdev --repository-url="https://packages.zendframework.com" zendframework/skeleton-application path/to/install
https://github.com/zendframework/ZendSkeletonApplication
http://zf2.readthedocs.org/en/latest/user-guide/overview.html
Modules
Modules in ZF1
http://www.flickr.com/photos/redux/4298421692
Modules in ZF2
http://www.flickr.com/photos/boltofblue/5460151040/
Project Layout
ZF1 ZF2
application
|- configs
|- controllers
|- IndexController.php
|- forms
|- Comment.php
|- layouts
|- scripts
|- layout.php
|- models
|- DbTable
|- Comment.php
|- Comment.php
|- CommentService.php
|- plugins
|- CallerPlugin.php
|- views
|- helpers
|- DayDifference.php
|- scripts
|- index
|- index.phtml
|- Bootstrap.php
config
module
|- Application
|- config
|- module.config.php
|- src
|- Application
|- Controller
|- IndexController.php
|- Form
|- Comment.php
|- Model
|- Comment.php
|- CommentService.php
|- View
|- Helper
DayDifference.php
|- view
|- application
|- index
|- index.phtml
|- layout
|- layout.phtml
|- Module.php
Project Layout
ZF1 ZF2
application
|- configs
|- controllers
|- IndexController.php
|- forms
|- Comment.php
|- layouts
|- scripts
|- layout.php
|- models
|- DbTable
|- Comment.php
|- Comment.php
|- CommentService.php
|- plugins
|- CallerPlugin.php
|- views
|- helpers
|- DayDifference.php
|- scripts
|- index
|- index.phtml
|- Bootstrap.php
config
module
|- Application
|- config
|- module.config.php
|- src
|- Application
|- Controller
|- IndexController.php
|- Form
|- Comment.php
|- Model
|- Comment.php
|- CommentService.php
|- View
|- Helper
DayDifference.php
|- view
|- application
|- index
|- index.phtml
|- layout
|- layout.phtml
|- Module.php
The Assets
Copy from ZF1:
/public
to ZF2:
/public
Ignoring index.php and .htaccess
(difficult)
The View
Separate object for the view data layer (ViewModel)
View rendering layer renamed to ViewRenderer
(catchy)
The Layout
Copy from ZF1:
application/layouts/scripts/layout.phtml
to ZF2:
module/Application/view/layout/
(yay!)
The Layout
Edit:
module/Application/view/layout/
Change
echo $this->layout()->content;
to
echo $this->content;
(the page should now render like...)
The Models
Copy from ZF1:
application/models/Comment.php
application/models/CommentService.php
to ZF2:
module/Application/src/Application/Model
Namespaces
Namespaces
Goodbye
Long_Underscore_Seperated_Class
Hello
Nice\Snappy\Namespaced\Class
The Models
Update the Services:
ZF1 - Application_Model_Comment
class Application_Model_Comment
{
ZF2 - Application\Model\Comment
namespace Application\Model;
class Comment
{
The Models
Update the Services:
ZF1 - Application_Model_CommentService
class Application_Model_CommentService
{
function __construct(
Application_Model_DbTable_Comment $commentTable)
The Models
Update the Services:
ZF2 - Application\Model\CommentService
namespace Application\Model;
use Zend\Db\TableGateway\TableGateway;
class CommentService
{
function __construct(TableGateway $commentTable)
The Form
http://hock.in/11SCIvU
The Form
Copy
application/forms/Comment.php
to
module/Application/src/Application/Form
The Form
Edit the form to update namespaces
(everything we copy will need this)
ZF1 - Application_Form_Comment
class Application_Form_Comment extends Zend_Form
{
ZF2 - Application\Form\Comment
namespace Application\Form;
use Zend\Form\Form;
class Comment extends Form
{
(last time I’m showing this)
The Form
Rewrite the entire thing
init() becomes __construct()
$this->setMethod('post');
becomes
$this->setAttribute('method', 'post');
The Form
$this->addElement(
'text',
'name',
array(
'label' => 'Your name',
'required' => true,
'filters' => array(
'StringTrim'
),
'validators' => array(
array(
'validator' => 'StringLength',
'options' => array(2, 128)
),
),
)
);
The Form
becomes
$this->add(
array(
'name' => 'name',
'attributes' => array(
'type' => 'text'
),
'options' => array(
'label' => 'Your name ',
),
)
);
The Form
and
$inputFilter = new InputFilter();
$inputFilter->add(array(
'name' => 'name',
'required' => true,
'filters' => array(array(
'name' => 'StringTrim',
)),
'validators' => array(array(
'name' => 'StringLength',
'options' => array(
'min' => 2,
'max' => 128,
)),
),
));
(excuse the formatting)
The Database
ZF1 - application.ini
resources.db.adapter = PDO_MYSQL
resources.db.isDefaultTableAdapter = true
resources.db.params.host = 127.0.0.1
resources.db.params.username = root
resources.db.params.password =
resources.db.params.dbname = commentizr
Intermission
Service Manager
http://sourceforge.net/apps/mediawiki/pagmo/nfs/project/p/pa/pagmo/1/15/Don_t_panic.jpg
The Database
ZF2 - config/autoload/db.local.php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=commentizr;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'root',
'password' => '',
),
);
Zend_Db_Table
ZF1 - Application_Model_DbTable_Comment
class Application_Model_DbTable_Comment extends Zend_Db_Table_Abstract
{
protected $_name = 'comment';
}
Table Gateway
ZF2 - Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Application\Model\CommentService' => function (ServiceManager $serviceManager) {
$commentTable = $serviceManager->get('Application\Model\CommentTable');
return new CommentService($commentTable);
},
'Application\Model\CommentTable' => function (ServiceManager $serviceManager) {
$dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$hydrator = new ClassMethods();
$rowObjectPrototype = new Comment();
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('comment', $dbAdapter, null, $resultSet);
return $tableGateway;
}
),
);
}
Table Gateway
ZF2 - Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Application\Model\CommentService' => function (ServiceManager $serviceManager) {
$commentTable = $serviceManager->get('Application\Model\CommentTable');
return new CommentService($commentTable);
},
'Application\Model\CommentTable' => function (ServiceManager $serviceManager) {
$dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$hydrator = new ClassMethods();
$rowObjectPrototype = new Comment();
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('comment', $dbAdapter, null, $resultSet);
return $tableGateway;
}
),
);
}
The Hydration
ZF1 - Application_Model_CommentService
public function fetchAll($referer = null, $limit = 10)
{
if(is_null($referer)) {
$referer = Zend_Registry::get('Referer');
}
$resultSet = $this->commentTable
->select()
->where('referer = ?', $referer)->order('created DESC')->limit((int)$limit)
->query()->fetchAll();
$return = array();
foreach ($resultSet as $result) {
$comment = new Application_Model_Comment();
$comment->setId($result['id']);
$comment->setName($result['name']);
$comment->setComment($result['comment']);
$comment->setCreated($result['created']);
$comment->setEmail($result['email']);
$comment->getReferer($result['referer']);
$return[] = $comment;
}
return $return;
}
Table Gateway
ZF2 - Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Application\Model\CommentService' => function (ServiceManager $serviceManager) {
$commentTable = $serviceManager->get('Application\Model\CommentTable');
return new CommentService($commentTable);
},
'Application\Model\CommentTable' => function (ServiceManager $serviceManager) {
$dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$hydrator = new ClassMethods();
$rowObjectPrototype = new Comment();
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('comment', $dbAdapter, null, $resultSet);
return $tableGateway;
}
),
);
}
Table Gateway
ZF2 - Module.php
public function getServiceConfig()
{
return array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Application\Model\CommentService' => function (ServiceManager $serviceManager) {
$commentTable = $serviceManager->get('Application\Model\CommentTable');
return new CommentService($commentTable);
},
'Application\Model\CommentTable' => function (ServiceManager $serviceManager) {
$dbAdapter = $serviceManager->get('Zend\Db\Adapter\Adapter');
$hydrator = new ClassMethods();
$rowObjectPrototype = new Comment();
$resultSet = new HydratingResultSet($hydrator, $rowObjectPrototype);
$tableGateway = new TableGateway('comment', $dbAdapter, null, $resultSet);
return $tableGateway;
}
),
);
}
The Service
Update the CommentService to take dependency injected:
ZF2 - Application\Model\CommentService
namespace Application\Model;
use Zend\Db\TableGateway\TableGateway;
class CommentService
{
function __construct(TableGateway $commentTable)
{
(we did this already earlier)
The Service
Update the CommentService because it no longer needs to hydrate an object:
ZF2 - Application\Model\CommentService
public function fetchAll($referer = null, $limit = 10)
{
if (is_null($referer)) {
$referer = $this->referer;
}
$select = new Select('comment');
$select->where(array('referer' => $referer));
$select->order('created DESC');
$select->limit($limit);
$return = $this->commentTable->selectWith($select);
return $return;
}
(should be fairly familiar)
The Service
ZF1 - Application_Model_CommentService
public function save(Application_Model_Comment $comment)
{
$data = array(
'name' => $comment->getName(),
'email' => $comment->getEmail(),
'comment' => $comment->getComment(),
'created' => new Zend_Db_Expr('NOW()'),
'referer' => Zend_Registry::get('Referer')
);
if (is_null($comment->getId())) {
return $this->commentTable->insert($data);
}
return $this->commentTable->update($data, array('id = ?'), $comment->getComment());
}
The Service
ZF2 - Application\Model\CommentService
public function save(Comment $comment)
{
$data = array(
'name' => $comment->getName(),
'email' => $comment->getEmail(),
'comment' => $comment->getComment(),
'created' => new Expression('NOW()'),
'referer' => $this->referer
);
if (is_null($comment->getId())) {
return $this->commentTable->insert($data);
}
return $this->commentTable->update($data, array('id' => $comment->getComment()));
}
(we could use hydrator’s “extract” method here)
The Controller
ZF2 - module/Application/config/module.config.php
delete
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\Index'
),
),
The Controller
ZF2 - Module.php
add
public function getControllerConfig()
{
return array('factories' => array(
'Application\Controller\Index' => function (ControllerManager $controllerManager) {
$commentService = $controllerManager
->getServiceLocator()->get('Application\Model\CommentService');
return new IndexController($commentService);
}
));
}
(We want to inject CommentService into the controller)
The Controller
ZF2 - Application\Controller\IndexController.php
class IndexController extends AbstractActionController
{
protected $commentService;
function __construct($commentService) {
$this->commentService = $commentService;
}
public function indexAction() {
$form = new CommentForm();
if ($this->getRequest()->isPost()) {
$form->setData($this->getRequest()->getPost());
if($form->isValid()) {
$this->commentService->save($form->getObject());
$this->redirect('/?referer=' . $this->commentService->getReferer());
}
} else {
$form->bind(new \Application\Model\Comment());
}
$form->get('referer')->setValue($this->commentService->getReferer());
$comments = $this->commentService->fetchAll();
return new ViewModel(array('form' => $form, 'comments' => $comments));
}
}
The View
Copy
views/scripts/index/index.phtml
to
module/Application/view/application/index
(view script locations are similar and can be defined)
The View
Edit
module/Application/view/application/index/index.php
$this->escape() => $this->escapeHtml()
$form->setAction() => $form->setAttribute('action', ...
echoing the form no longer works as there are no decorators ;)
The View
Form View Helpers:
<?php
$form->setAttribute('action', $this->url());
$form->prepare();
echo $this->form()->openTag($form);
echo $this->formCollection($form);
echo $this->form()->closeTag();
?>
The Front Controller Plugin
ZF1 - Application_Plugin_CallerPlugin
class Application_Plugin_CallerPlugin extends Zend_Controller_Plugin_Abstract
{
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
if(is_null($request->getServer('HTTP_REFERER'))
&& is_null($request->getParam('referer'))) {
throw new Exception('REFERER is not set!');
}
if(!is_null($request->getParam('referer'))) {
$referer = $request->getParam('referer');
} else {
$referer = $request->getServer('HTTP_REFERER');
}
Zend_Registry::set('Referer', $referer);
}
}
(don’t do this)
The Event Manager
ZF2 - Module.php
public function onBootstrap(MvcEvent $event)
{
$request = $event->getRequest();
if (is_null($request->getServer('HTTP_REFERER')) && is_null($request->getPost('referer'))
&& is_null($request->getQuery('referer'))
) {
throw new \Exception('REFERER is not set!');
}
$commentService = $event->getApplication()->getServiceManager()->get('Application\Model\CommentService');
if(!is_null($request->getPost('referer'))) {
$commentService->setReferer($request->getPost('referer'));
return true;
}
if(!is_null($request->getQuery('referer'))) {
$commentService->setReferer($request->getQuery('referer'));
return true;
}
if(!is_null($request->getServer('HTTP_REFERER'))) {
$commentService->setReferer($request->getServer('HTTP_REFERER'));
return true;
}
}
(do do this)
The View Helper
ZF1 - Zend_View_Helper_DayDifference
public function DayDifference(Zend_Date $date1, Zend_Date $date2 = null)
{
$date1 = new DateTime($date1->get(Zend_Date::ISO_8601));
if ($date2 === null) {
$date2 = new Zend_Date();
}
$date2 = new DateTime($date2->get(Zend_Date::ISO_8601));
$diff = $date1->diff($date2);
...
if($diff->h > 0) {
return ($diff->h === 1) ? $diff->h . ' hour ago' : $diff->h . ' hours ago';
}
if($diff->i > 0) {
return ($diff->i === 1) ? $diff->i . ' minute ago' : $diff->i . ' minutes ago';
}
if($diff->s > 0) {
return ($diff->s === 1) ? $diff->s . ' second ago' : $diff->s . ' seconds ago';
}
return 'Right now';
}
The View Helper
ZF2 - Application\View\Helper\DayDifference
public function __invoke(\DateTime $date1, \DateTime $date2 = null)
{
if ($date2 === null) {
$date2 = new \DateTime();
}
$diff = $date1->diff($date2);
....
if ($diff->d > 0) {
return ($diff->d === 1) ? $diff->d . ' day ago' : $diff->h . ' days ago';
}
if($diff->h > 0) {
return ($diff->h === 1) ? $diff->h . ' hour ago' : $diff->h . ' hours ago';
}
if($diff->i > 0) {
return ($diff->i === 1) ? $diff->i . ' minute ago' : $diff->i . ' minutes ago';
}
if($diff->s > 0) {
return ($diff->s === 1) ? $diff->s . ' second ago' : $diff->s . ' seconds ago';
}
return 'Right now';
}
The View Helper
Now we tell the ViewHelperManager how to load the view helper:
ZF2 - Module.php
public function getViewHelperConfig()
{
return array(
'invokables' => array(
'DayDifference' => 'Application\View\Helper\DayDifference',
),
);
}
(you really should know this pattern by now)
It Works!
(my wonderful family)
It Doesn’t Work!
Gary Hockin
@GeeH on Twitter
GeeH on IRC (Freenode #roave)
https://github.com/Spabby/zendcon-zf1
https://github.com/Spabby/zendcon-zf2
QUESTIONS?
RATE ME OR ELSE!!!
https://joind.in/10862
http://whatculture.com/film/10-movie-villains-who-were-more-far-interesting-than-the-heroes.php