Pragmatism in the real world

Updated tutorial for Zend Framework 2 beta 1

With the announcement of Zend Framework beta 1, I have updated my venerable tutorial to work with it!

Getting started with Zend Framework 2 (beta1), creates the same application as my ZF1 tutorial, so it should be very familiar, but this time, it’s in the context of Zend Framework 2. As usual, it’s a PDF too.

Please download it, try it out and let me know if you find any typos!

44 thoughts on “Updated tutorial for Zend Framework 2 beta 1

  1. Brilliant, thank you! I never really took the plunge with zf, and now that 2 is on the horizon I'm finally gonna take a look :) thanks for your hard work!

  2. Hey Rob,
    great work thanks for sharing… I have noticed two minor glitches:

    Module.php:
    when calling getConfig() I got an Notice: Undefined variable: env
    If I add it as a parameter of the function getConfig($env = null) it stops complaining.

    modules/Album/views/album/index.phtml:
    there is a typo $this->$this->headTitle($title); which throws an Catchable fatal error: Object of class ZendViewPhpRenderer could not be converted to string
    just remove change to $this->headTitle($title);

    hope this helps other people reading this tutorial…

  3. Class Zend_Registry isn't provided in the current beta zip file.
    So when you start with the skeleton application you get an error on Zend/View/Helper/Registry

  4. Hello Akrabat,
    As I am following the tutorial, which looks great I saw one mistake and one typo.

    Mistake: the autoload_classmap.php should be in modules/Album and not in Album.

    The Typo is on page 8 second line "generalluy"

    But anyways thanks very much for the tutorial. Looking forward to the followup.

  5. Hi Rob,

    I've worked through your tutorial.
    Great start and good explaining.

    I've found a few minor bugs.
    In AlbumModelAlbums.php in getAlbum there is an Exception thrown. However Exception class doesn't exist in current namespace. To resolve this you have to add before Exception
    So it becomes throw new Exception

    One more thing in your pdf on page 14 under paragraph 'Listing Albums' there is a reference to file modules/Album/src/Album/IndexController
    It should be AlbumController.

    Thanks for sharing!

  6. Getting: Fatal error: Class 'ZendFormForm' not found in C:wwwApache2htdocszf2tutorialmodulesAlbumsrcAlbumFormAlbumForm.php on line 22

    Code:

    namespace AlbumForm;

    use ZendFormForm,
    ZendFormElement;

    class AlbumForm extends Form
    {
    public function init()

    Any idea?

  7. I get exception:
    Fatal error: Class 'ZendDbProfiler' not found in /home/fred/html/zf2tutorial/library/Zend/Db/Adapter/AbstractAdapter.php on line 368 Call Stack: 0.0003 334048 1. {main}() /home/fred/html/zf2tutorial/public/index.php:0 0.0917 2776644 2. ZendMvcApplication->run() /home/fred/html/zf2tutorial/public/index.php:35 0.1010 3295980 3. ZendEventManagerEventManager->trigger() /home/fred/html/zf2tutorial/library/Zend/Mvc/Application.php:223 0.1010 3295984 4. ZendEventManagerEventManager->triggerListeners() /home/fred/html/zf2tutorial/library/Zend/EventManager/EventManager.php:204 0.1014 3297268 5. call_user_func() /home/fred/html/zf2tutorial/library/Zend/EventManager/EventManager.php:418 0.1014 3297284 6. ZendMvcApplication->dispatch() /home/fred/html/zf2tutorial/library/Zend/EventManager/EventManager.php:418 0.1015 3297284 7. ZendDiDi->get() /home/fred/html/zf2tutorial/library/Zend/Mvc/Application.php:288 0.1015 3297692 8. ZendDiDi->newInstance() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:129 0.1194 3705388 9. ZendDiDi->handleInjectionMethodForObject() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:193 0.1194 3705488 10. ZendDiDi->resolveMethodParameters() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:329 0.1198 3707104 11. ZendDiDi->get() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:525 0.1198 3707396 12. ZendDiDi->newInstance() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:129 0.1452 3734516 13. ZendDiDi->createInstanceViaConstructor() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:172 0.1454 3734736 14. ZendDiDi->resolveMethodParameters() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:269 0.1496 4052420 15. ZendDiDi->get() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:525 0.1497 4052712 16. ZendDiDi->newInstance() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:129 0.1632 4057028 17. ZendDiDi->createInstanceViaConstructor() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:172 0.1644 4080252 18. ZendDbAdapterAbstractAdapter->__construct() /home/fred/html/zf2tutorial/library/Zend/Di/Di.php:277 0.1646 4081724 19. ZendDbAdapterAbstractAdapter->setProfiler() /home/fred/html/zf2tutorial/library/Zend/Db/Adapter/AbstractAdapter.php:257

  8. Hello Rob!
    After going through the tutorial step by step, when testing in the browser for the second time – Album list, I get an error: "An error occurred Page not found.", but the default host/index/ controller works well and shows up. Tested by doing die()'s through every file and none of the Album files – controller/model respond, only the config files.
    Could you make a guess where could be the problem? Thank you in advance!

  9. Noticed this: you have in application.config.php

    return new ZendConfigConfig(array(

    but my version has
    return array(

    tried to change but get errors

  10. Cool had same Error as @Fred. I had this problem in earlier ZF2 dev versions too.
    Has someone a solution?

    Fatal error: Class 'ZendDbProfiler' not found in /usr/share/zendlib/zf2/library/Zend/Db/Adapter/AbstractAdapter.php on line 368

  11. Hi Rob,

    I find typo on page 8: path to controller should not be
    "modules/Album/src/Album/AlbumController.php:"
    but
    "modules/Album/src/Album/Controllers/AlbumController.php:"
    This path is above the code of the controller.

    Rob, I want to translate this document into Russian. But pdf not a very good format for editing on Linux. Do you have this text in another format?

  12. He @Fred, which PHP Version do you use! I'm working still on my "Class 'ZendDbProfiler' not found" problem.

    Maybe there is some PHP-Namespace trouble in it?

    I use 5.3.2 (UBUNTU 10.04 LTS SERVER (64bit))

  13. Hi Rob,
    great tutorial.

    Can you also elaborate the impact of the following statement:

    "As you can see, we have loaded our Album module before the Application module. This convention
    exists as we expect that you will install third-party modules in your application and will override their default configuration by editing the Application module’s configuration file."

    This will also impact the custom routes defined in the module – IF ANY. In the current implementation module routes will be assembled but not matched. If you want the custom routes for your module to be matched then you need to put 'Album' after 'Application' in the module list, or override the routes by moving them from the Album module to the 'Application' Module.

    Again great job!

    Nick

  14. Hi @Master B. and @Fred,

    yesterday I ran in the same problems like you and I've found the solution.
    I also use ubuntu 10.4 with PHP 5.3.2 installed.
    I've recognized that something like:

    $className = 'ZendDbProfile';
    $profiler = new $className();

    does not work correctly.
    changing the line to:

    $profiler = new ZendDbProfile();

    makes it work as aspected.
    But you get the next fatal error with ZendDbTableRowset …

    Today I've updated my PHP Installation to PHP 5.3.5 and everything works fine. One possibility to upgrade php is shwon on this page:
    http://www.zalexblog.com/2011/01/07/installing-php-5-3-3-on-ubuntu-10-04/

    Hope it helps.

  15. Hi @codeliner

    Thanks, yes I found out too that there's a problem with the PHP Version on Ubuntu. It's strange that only ZendDb sucks on this problem, there must be an Bug on it.

    Yes, Ubuntu should update the PHP repository. I dont like manually update this library, but maybe there is no other way.

  16. @mtvic
    I had the same error. The location to put AlbumController is wrong as stated by Oleg Lobach two post below yours. Though there is a typo in the answer

    /modules/Album/src/Album/Controller/AlbumController.php

    Above is the correct place that got it working. Sometimes it's better to think than just go step by step through a tutorial =) (it all makes sence when you find the solution).

    @akrabat The typo we're talking about is on page 8 "Create the Controller".

  17. NickBelhomme,
    Good point about routes. I'll have to think about that situation a bit more.

    Christoffer & mtvic,
    Thanks! Fixed.

    Regards,

    Rob…

  18. Hey, I was following it all and when I was doing Forms I was getting an error about not being able to find ZendControllersFront

    So I had a look and neither the Full or Minimal packages of ZF2 include a controllers/front folder of any sort.

    I downloaded from github and managed to get the missing pieces… not sure what else was missing but yeah.

    Maybe worth an update to say that they should download it from GitHub or for Zend to update that package :D

    Absolutely love this tutorial. Been ripping my hair out trying to get into Zend for the first time then decided to get into ZF2. Your tutorial is the ONLY thing that actually gets me off my feet.

    Thanks

  19. I couldn't figure out why I was having issues getting ZF2 running. I skipped the VirtualHost step because I usually organize projects like http://my-domain/client-name/project-name/public/ while I'm in development and don't move to a virtual host until production.

    I've done that for 3 years with ZF without any issues and it always handles the paths correctly, but for some reason ZF2 wouldn't run like that (always gets page not found). I eventually setup a VirtualHost and voila. Any idea how I can get it to run using the full path without having to setup a virtual host for each project?

  20. Ok, I'm sure I'm missing something very obvious; however, I can't get the initial ZF2 skeleton to work.

    The error I'm receiving is the following:

    Fatal error: Interface 'ZendModuleConsumerAutoloaderProvider' not found in /path/to/zf2tutorial/modules/Application/Module.php on line 10

    At this point all I've done is:
    1. Downloaded the ZF2 skeleton & ZF2 framework, placing the "Zend" directory into "zf2tutorial/Library/" directory.
    2. Setup the apache virtual host.
    3. Restarted apache.
    4. Loaded the index page.

    So I look into the zf2tutorial/Library/Zend/Module folder and I don't see a "Consumer" directory which from the error message I'd expect to see.

    I'm not sure if I'm missing something or if the "zf2tutorial/modules/Application/module.php" file needs to be modified.

    Any thoughts?

    1. Chris,

      It's very possible that the ZF Skeleton has evolved to stay compatible with the latest version of ZF2. Try the zip file download on the tutorial page.

      Regards,

      Rob…

  21. Rob, I must not be as bright as the other folks using your tutorial. I started the Zend Framework 2 tutorial and go all the way to page 3. I tried to open the page then when I get this error. PHP Fatal error: Interface 'ZendModuleConsumerAutoloaderProvider' not found in C:vHostszf2tutorialmodulesApplicationModule.php on line 10

    The only files I see are
    ZendModuleManager.php
    ManagerOptions.php
    README.md

    Can you please advise me of what I am doing wrong here? Thanks, Frank.

    PS: I love your tutorials, I do have 1.11.11 working.

  22. So, with my last git ZF2 pull request. The App is broken. There was a "Module manager refactoring" ….

  23. Just wanna correct myself from before. I originally said that the ZF2 Beta1 that was on their website was missing things like /Controller/ and that I could get it straight from Git but I now see that the Controller was moved to /mvc/ and it seems to be that way in your tutorial as well :)

  24. Hey Rob, sorry to post many times but have a question. In your example you're injecting the DB Adapter directly into the model which is extending Zend Table. Great idea but I have about 90 tables in total. Should I be copy and pasting the injection code for each table class or is there a way to just do it once? I've tried injecting it straight into AbstractTable, tried injecting it into Table and I've tried creating a wrapper class which extends Table and then each of my tables extends this but to no success!

    Thanks, Dom

  25. Page 12: Location of file should be – modules/Album/src/Album/Controller/AlbumController.php

    Page 14: Location and name of the file is also incorrect here. You have the file named IndexController.php when it should be AlbumController.

  26. Firstly, many thanks for the great tutorial. I went through this and successfully set up the project.
    I found some other similar tutorials and they seem to copy the way ZF 1.x used to work but I prefer this whole new better way with use of DI and events.
    Only question I have is, I'm missing the custom bootstrap class I used to create with ZF1.x, where I could create methods like initDatabase() or initCache() etc and it used to execute before application runs.
    Would it be possible to elaborate a little bit on that,how can we add custom initXXXX methods with bootstrap?
    I'm trying to integrate Doctrine with ZF2.0 and struggling a little bit just because of this (I believe).

    Thanks once again.
    P

  27. Nice tutorial, while going through, I noticed that the parameters nature and order for the URL view help have changed from :

    $this->url(
    array(urlParams), array(route(s))
    )

    to

    $this->url(
    route, array(urlParams)
    )

  28. Thank you for the awesome book and tutorials. I was playing with zf2 and was wondering how to integrate phpunit into zf2 for module testing. How to make use of the DI for testing and what is the proper way to set up the unit testing in zf2? Thanks and looking forward to more good ones!

  29. Hi!
    What happened to $this->view->var = 'value'; style of variable assignment in controllers? Deprecated?

    Is it just me, or ZF2 is starting to look a lot like Yii?

    What happened to application env sections in the config files?

  30. Further to Jeff's comments about the View Helper URL method changes.

    I was getting "An error occurred during execution" on each of the calls to $this->url in the views.

    The code for index.phtml (and other uses of $this->URL) would follow this format:

    <a href="url('default', array('controller'=>'album', 'action'=>'edit', 'id' => $album->id ));?>">Edit
    <a href="url('default', array('controller'=>'album', 'action'=>'delete', 'id' => $album->id ));?>">Delete

  31. v0.1.5, page 14: redundant ')' sign in index.phtml

    here:
    <a href="url('default', array('controller'=>'album',
    'action'=>'add')));?>">Add new album

  32. Hi Rob,
    Just downloaded version 0.2.0 of your great tutorials. However, I saw on page 6 "Configuration) that there is no return of $default in ./module/Album/config/module.config.php Did you fix this already? I replaced $default= with return and I have part 1 of the tutorial working.

    Everyone, please take care of those nested arrays. It took me hours to figure out where in the config files I missed a ')' which gives nasty errors… (yes, it was completely my bad…)

  33. @Dominic Watson, Regarding the config used in DI injection. I agree, this seems difficult to maintain. One way to resolve this issue would be to setup the dependency injection in code instead of config.

    In you module init method subscribe to the bootstrap (see applicationviewlistener as an example):

    $events->attach('bootstrap', 'bootstrap', array($this, 'initializeDi'), 100);

    Then you can setup the container parameters in the callback using config:

    public function initializeDi($e){
    $app = $e->getParam('application');
    $locator = $app->getLocator();
    $config = $e->getParam('config');

    $locator->instanceManager()->setParameters('yourclass', array(
    'foo' => $config->bar
    ));
    }
    Now I'm not sure that this is the correct way to do it, but it seems to be the way to keep it maintainable.

  34. Hi Everyone,

    I've been battling trying to change the layout for specific pages

    I've tried both of the following

    within the controller indexAction()
    $this->_helper->_layout->setLayout('layout2');

    This returns an error of
    PHP Notice: Undefined property: TestControllerTestController::$_helper
    and
    PHP Fatal error: Call to a member function setLayout() on a non-object in

    then I have also tried within the index.phtml
    $this->layout()->setLayout('layout2');

    this does not cause php errors… however it did not load the layout at all.
    Upon further investigating,
    $this->layout()->getLayout()
    returns the correct value, but it seems to pass this after the default layout has already been loaded… ie it loads layout.phtml then changes the layout (which is too late and is ignored) then loads the content of index.phtml

    Any suggestions or ideas?

    Thanks in advance,
    T

  35. Ok,

    So my initial findings weren't quite corrent and I found a partial fix on a french forum

    http://www.z-f.fr/forum/viewtopic.php?id=7092
    post #6

    they modified the renderLayout () of Listener.php to fix disabling layout
    $this->getLocator()->get('view')->layout()->disableLayout();

    from this i've done some fiddling and made a rudimentary fix, but I'm not very familiar ZF2 or ZF1 and there is bound to be a more efficient way.

    within a controller you can now do any of the following
    $this->getLocator()->get('view')->layout()->setLayout('layouts/ajax.phtml');
    $this->getLocator()->get('view')->layout()->setLayout('ajax');
    $this->getLocator()->get('view')->layout()->disableLayout();

    within a view phtml file you can do
    $this->layout()->setLayout('layouts/ajax.phtml');
    $this->layout()->setLayout('ajax');
    $this->layout()->disableLayout();

    below is the change required in renderLayout() of Listener.php

    /*
    //————————— Original Code —————————-
    $layout = $this->view->render($this->layout, $vars);
    $response->setContent($layout);
    return $response;
    */
    //———————- Fix For Disable Layout ——————–
    if(($this->layout !== $this->view->layout()->getLayout())&&(strstr($this->view->layout()->getLayout(),'.phtml'))){
    // If the getLayout is different from default layout and contains .phtml
    $this->layout = $this->view->layout()->getLayout();
    }elseif((basename($this->layout, ".phtml")!==$this->view->layout()->getLayout())&&!(strstr($this->view->layout()->getLayout(),'phtml'))){
    // If default layout filename (without phtml) does not equal getLayout then select differnet view file within the same directory as the default layout
    $this->layout = dirname($this->layout).'/'.$this->view->layout()->getLayout().'.phtml';
    }
    $layout = $this->view->render($this->layout, $vars);
    return ($this->view->layout()->isEnabled()) ? $response->setContent($layout) : $response->setContent($vars['content']);

    //——————————————————————

Comments are closed.