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!
Awesome! Thank you.
Oh nice!
That's I'm waiting for since a while.
Thanks!
Thanks, it's great.
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!
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…
Thanks Richard,
I've updated the PDF.
Regards,
Rob…
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
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.
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!
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?
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
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!
Noticed this: you have in application.config.php
return new ZendConfigConfig(array(
but my version has
return array(
tried to change but get errors
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
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?
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))
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
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.
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.
@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".
NickBelhomme,
Good point about routes. I'll have to think about that situation a bit more.
Christoffer & mtvic,
Thanks! Fixed.
Regards,
Rob…
@Master B. I have Centos 6 and PHP 5.3.2. Distro has no PHP updates so far
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
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?
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?
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…
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.
So, with my last git ZF2 pull request. The App is broken. There was a "Module manager refactoring" ….
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 :)
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
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.
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
Puru,
Add to a Module.php.
Regards,
Rob…
@Puru Ji
If you're trying to integrate Doctrine into ZF2 I'd suggest you take a look at this: http://modules.zendframework.com/
There are loads of examples of apps with Doctrine2 on the new modules.zf site :D
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)
)
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!
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?
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
v0.1.5, page 14: redundant ')' sign in index.phtml
here:
<a href="url('default', array('controller'=>'album',
'action'=>'add')));?>">Add new album
Hey!
In my previouse comment (#39) part of the code vanished. Apparently cut by filters.
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…)
@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.
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
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']);
//——————————————————————