ZF2 autoloading custom modules with composer - zend-framework2

I'm trying to setup a ZF2 project (slightly different from the zf2skeleton) and I want to use composer to deal with all the autoloading, not only from the vendor ones (installed through composer) but also those modules I create.
For some reason, i can't get access to my Application module Index controller. I think its the autoloading that's not working... I just don't know what i might be doing wrong..
Thanks!
Files and data below:
This is my folder structure:
index.php
private
- modules
-- Aplication
--- src
----- Aplication
------- Controller
---------- IndexController.php
- vendor
-- zendframework
-- composer
-- autoload.php
- composer.json
- composer.phar
main.config.php
return array(
'modules' => array(
'Application',
),
'module_listener_options' => array(
'config_glob_paths' => array(
'private/config/autoload/{,*.}{global,local}.php',
),
'cache_dir' => realpath(dirname(__DIR__) . '/../../data/cache'),
'module_paths' => array(
realpath(__DIR__ . '/../module'),
realpath(__DIR__ . '/../vendor'),
),
),
);
index.php
include_once 'private/vendor/autoload.php';
$application = Zend\Mvc\Application::init(include 'private/config/main.config.php');
return $application;
composer.json
{
"repositories": [
{
"type": "composer",
"url": "http://packages.zendframework.com/"
}
],
"require": {
"php": ">=5.3.3",
"zendframework/zendframework": "2.*"
},
"autoload": {
"psr-0": {
"Application\\": "module/Application/src"
}
}
}
Application config
return array(
'router' => array(
'routes' => array(
'home' => array(
'type' => 'Zend\Mvc\Router\Http\Literal',
'options' => array(
'route' => '/',
'defaults' => array(
'controller' => 'Application\Controller\Index',
'action' => 'index',
),
),
),
),
),
'controllers' => array(
'invokables' => array(
'Application\Controller\Index' => 'Application\Controller\IndexController'
),
),
);
IndexController
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class IndexController extends AbstractActionController {
public function indexAction() {
die("app ok");
}
}

First, from what I see, you don't run your application :
$application = Zend\Mvc\Application::init(include 'private/config/main.config.php');
$application->run();
Another point is that, you don't have to use composer to load your modules. As your application config already include the module directory, the Module loading process will automatically scan the directory and use the loading strategy defined at the level your Module classes.

Related

Class 'Album\Controller\AlbumController' not found

When i try to start album application an error message appears:
Fatal error: Class 'Album\Controller\AlbumController' not found in
C:\xampp\htdocs\ZendSkeletonApplication\vendor\zendframework\zendframework\library\Zend\ServiceManager\AbstractPluginManager.php
on line 170
This is my module.config.php file code
<?php
return array(
'controllers' => array(
'invokables' => array(
'Album\Controller\Album' => 'Album\Controller\AlbumController',
),
),
// Added to make router
'router' => array(
'routes' => array(
'album' => array(
'type' => 'segment',
'options' => array(
'route' => '/album[/][:action][/:id]',
'constraints' => array(
'action' => '[a-zA-Z][a-zA-Z0-9_-]*',
'id' => '[0-9]+'
),
'defaults' => array(
'controller' => 'Album\Controller\Album',
'action' => 'index',
),
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'album' => __DIR__ . '/../view',
),
),
);
And this is AlbumController.php file code:
<?php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
class AlbumController extends AbstractActionController {
protected $albumTable;
public function indexAction() {
return new ViewModel(array(
'album' => $this->getAlbumTable()->fetchAll(),
));
}
public function addAction() {
}
public function editAction() {
}
public function deleteAction() {
}
public function getAlbumTable () {
if (!$this->albumTable) {
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
}
i see you are just getting started, so i would refer to this code by Martin Shwalbe and find out if you have any typo. If everything looks good, then you probably have issue in the way you are accessing it.
https://github.com/Hounddog/Album
hope this helps...

ZF2 - ZfcUser unable to change view scripts

I'm very new to Zend Framework. I can't manage to override the view scripts of the ZfcUser module. I downloaded ZfcUser into the vendor directory. And I made the custom module and changed the routing. However, no luck changing the viewscripts.
I changed the url to profile instead of user. And made these configurations to include the override of the view scripts. However I am still getting the default scripts from the vendors folder. Would truly appreciate your help.
<?php
namespace Profile;
use Zend\Mvc\MvcEvent;
class Module
{
public function getConfig()
{
return array (
'router' => array (
'routes' => array (
'zfcuser' => array (
'options' => array (
'route' => '/profile',
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'profile' => __DIR__ . '/../view',
),
),
);
}
}
And here's an image of the directory
Ok here's how I got it fixed.. seems like it's nowhere in the documentation but it worked. I changed the view manager to look like this:
'zfcuser' => __DIR__ . '/view',
instead of
'profile' => __DIR__ . '/../view',
The only issue is that all the view scripts have to be imported in the custom module and overridden. Here's the results from the Module.php file in the custom module.
<?php
namespace Profile;
use Zend\Mvc\MvcEvent;
class Module
{
public function getConfig()
{
return array (
'router' => array (
'routes' => array (
'zfcuser' => array (
'options' => array (
'route' => '/profile',
),
),
),
),
'view_manager' => array(
'template_path_stack' => array(
'zfcuser' => __DIR__ . '/view',
),
),
);
}
}

Chaining Dependency Injection in ZF2

I am trying to create a simple email templating test in ZF2, I am using Dependency injection in order to create an instance of the PhpRenderer class, with all the dependencies set.
It appears that I may be struggling with chaining the injections as the path 'email' is not present in the AggregateResolver.
inside module.config.php
'di' => array(
'instance' => array(
'Zend\View\Resolver\TemplatePathStack' => array(
'options' => array(
'script_paths' => array(
'email' => __DIR__ . '/../view/application/email',
),
),
),
'Zend\View\Resolver\AggregateResolver' => array(
'attach' => array(
'Zend\View\Resolver\TemplatePathStack',
),
),
'Zend\View\Renderer\PhpRenderer' => array(
'setResolver' => 'Zend\View\Resolver\AggregateResolver',
),
),
),
inside TestController.php
$di = new \Zend\Di\Di;
$renderer = $di->get('Zend\View\Renderer\PhpRenderer');
$content = $renderer->render('email/test', null);
echo($content);
Message:
Zend\View\Renderer\PhpRenderer::render: Unable to render template "email/test"; resolver could not resolve to a file
Any help would be gratefully received.
Since writing the above, I was playing around and removed the TemplatePathStack from the di array and this had no effect at all, So I am not sure it is being used at all by the AggregateResolver, so it may be a chaining issue:
'di' => array(
'instance' => array(
/*'Zend\View\Resolver\TemplatePathStack' => array(
'addPaths' => array(
'paths' => array(
'email' => __DIR__ . '/../view/application/email',
),
),
),*/
'Zend\View\Resolver\AggregateResolver' => array(
'attach' => array(
'Zend\View\Resolver\TemplatePathStack',
),
),
'Zend\View\Renderer\PhpRenderer' => array(
'setResolver' => 'Zend\View\Resolver\AggregateResolver',
),
),
),
Aborgrove
In the end I solved it by moving the di array out of the module.conf.php and recreating it in the Module getServiceConf() method. (Although I am not sure this is the best place to put it)
public function getServiceConfig()
{
return array(
'factories' => array(
// using the Session Manger to create one instance of the follwing models
......... more code here ............
'EmailTemplatePathStack' => function($sm) {
$template_path_stack = new \Zend\View\Resolver\TemplatePathStack();
$paths = array('emailfolder' => __DIR__ . '/view/application/email');
$template_path_stack->addPaths($paths);
return $template_path_stack;
},
'EmailAggregateResolver' => function($sm) {
$resolver = new \Zend\View\Resolver\AggregateResolver();
$resolver->attach($sm->get('EmailTemplatePathStack'));
var_dump($resolver);
return $resolver;
},
'EmailPhpRenderer' => function($sm) {
$php_renderer = new \Zend\View\Renderer\PhpRenderer();
$php_renderer->setResolver($sm->get('EmailAggregateResolver'));
return $php_renderer;
},
),
);
}
Then changing the controller to:
$sm = \Application\Model\ServiceLocatorFactory::getInstance();
$renderer = $sm->get('EmailPhpRenderer');
$content = $renderer->render('test.phtml', null);
echo($content);

ZF2: Zend Framework 2.0.3 (Routing Not Working - Controller Not Found)

I setup a demo project and got routing to work between 2 different modules. However on my real application, having the Application module and a Restful module, my restful module router picks up but the controller cannot be found.
I am accessing it like localhost/restful/token/json/1
In my Module.php I have an onDispatch which I am using to dump the RouteMatch and I can see my route is actually being picked up.
$mvcEvent->getRouteMatch()
object(Zend\Mvc\Router\Http\RouteMatch)#185 (3) {
["length":protected]=>
int(19)
["params":protected]=>
array(2) {
["controller"]=>
string(5) "token"
["format"]=>
string(4) "json"
}
["matchedRouteName":protected]=>
string(7) "restful"
}
When Zend is trying to load the controller, it is merely passing token to the DispatchListener::get and through all the parents until it finally throws an exception that it cannot load the controller. Specifically, the final exception gets thrown in DispatchLister::onDispatch with $application::ERROR_CONTROLLER_NOT_FOUND.
The root exception being thrown is:
Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for "token".
Stack Trace:
#0 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/ServiceManager/AbstractPluginManager.php(110): Zend\ServiceManager\ServiceManager->get('token', false)
#1 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/Mvc/Controller/ControllerManager.php(114): Zend\ServiceManager\AbstractPluginManager->get('token', Array, false)
#2 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/Mvc/DispatchListener.php(90): Zend\Mvc\Controller\ControllerManager->get('token')
#3 [internal function]: Zend\Mvc\DispatchListener->onDispatch(Object(Zend\Mvc\MvcEvent))
#4 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/EventManager/EventManager.php(468): call_user_func(Array, Object(Zend\Mvc\MvcEvent))
#5 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/EventManager/EventManager.php(208): Zend\EventManager\EventManager->triggerListeners('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#6 /usr/local/zend/apache2/htdocs/EMRAuth/vendor/ZF2/library/Zend/Mvc/Application.php(297): Zend\EventManager\EventManager->trigger('dispatch', Object(Zend\Mvc\MvcEvent), Object(Closure))
#7 /usr/local/zend/apache2/htdocs/EMRAuth/public/index.php(22): Zend\Mvc\Application->run()
#8 {main}
I did the same dump in the Application module and it is actually passing the full namespaced controller name. As well in my demo project, in the extra module it is doing the same.
So I am not sure what I am doing wrong in this new project, but everything looks the same as my demo project. But its always just passing into the DispatchListener "token" instead of the actual controller.
module.config.php
return array(
'controllers' => array(
'invokables' => array(
'Restful\Controller\Token' => 'Restful\Controller\TokenController'
),
),
'router' => array(
'routes' => array(
'restful' => array(
'type' => 'Zend\Mvc\Router\Http\Segment',
'options' => array(
'route' => '/restful[/:controller[/:format][/:id]]',
'constraints' => array(
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'format' => '(xml|json|sphp)',
'id' => '[1-9][0-9]*',
),
'defaults' => array(
'__NAMESPACE__' => 'Restful\Controller',
'controller' => 'Restful\Controller\Token',
'format' => 'json',
),
),
),
),
),
'di' => array(
'instance' => array(
'alias' => array(
'dispatcher' => 'Restful\Response\Dispatcher',
),
'Restful\Response\Dispatcher' => array(
'parameters' => array(
'options' => include(__DIR__ . '/dispatcher.config.php')
),
),
),
),
);
Module.php
namespace Restful;
use Zend\EventManager\StaticEventManager;
class Module
{
protected static $options;
public function init(\Zend\ModuleManager\ModuleManager $moduleManager)
{
$events = StaticEventManager::getInstance();
$events->attach('Zend\Mvc\Controller\RestfulController','dispatch', array($this, 'onDispatch'), -100);
$events->attach('Zend\Mvc\Application','dispatch.error', array($this, 'onDispatch'),-100);
}
public function getConfig() {
return include __DIR__ . '/config/module.config.php';
}
public function onDispatch(\Zend\Mvc\MvcEvent $mvcEvent)
{
$result = $mvcEvent->getResult();
var_dump($mvcEvent->getRouteMatch());
if ($mvcEvent->isError())
{
$vars = $result->getVariables();
$errorId = $vars->offsetGet('reason');
$errorMessage=$vars->offsetGet('message');
$content = array(
'error' => (is_null($errorId)) ? 'notfound-error' : $errorId,
'message' => $errorMessage,
);
} else {
$content = array(
'content' => (is_array($result)) ? $result : $result->getVariables(),
);
}
$match = $mvcEvent->getRouteMatch();
$format = (empty($match)) ? 'json' : strtolower($mvcEvent->getRouteMatch()->getParam('format'));
$dispatcher = $mvcEvent->getTarget()->getServiceManager()->get('dispatcher');
return $dispatcher->render($format, $content, $mvcEvent->getResponse());
}
}
TokenController.php
namespace Restful\Controller;
class TokenController extends \Zend\Mvc\Controller\AbstractRestfulController
{
public function getList()
{
return array(
1 => array(
'id' => 1,
'title' => 'Title #1',
),
2 => array(
'id' => 2,
'title' => 'Title #2',
),
);
}
public function get($id)
{
return array(
'id' => $id,
'title' => 'Title #1',
);
}
public function create($data)
{
}
public function update($id, $data)
{
}
public function delete($id)
{
}
}
Your issue is that you defined parameter :controller in your route, which supersede default controller you specified.
Change your route definition to '/restful[/token[/:format][/:id]]'
As unrelated note: you must not specify data format as part of resource uri in RESTful API, pass it as get paramater ?format=xml or use proper content negotiation mechanism in HTTP protocol.
Good HTTP header implementation in zf2 should help you in that.

ServiceNotFoundException in ZendFramework 2, example from Rob Allen

for the past few weeks I have been following ZF2 especially Rob Allen's 'Album' example , I have created the example DB-'zf2tutorial' and example table-'album', which works fine fetching all the items when I use php-mysql, so problems with the data in the DB.
My local.php looks like this
config.autoload/local.php:
return array(
'db' => array
(
'driver' => "Pdo",
'dsn' => "mysql:dbname=zf2tutorial;hostname=localhost",
'username' => "user", //here I added my valid username
'password' => "password", //here I added my valid password
'driver_options' => array
(
PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES 'UTF8'"
),
),
);
Module.php
**module/Album/Model.php
<?php
namespace Album;
use Album\Model\AlbumTable;
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 getServiceConfiguration()
{
return array(
'factories' => array(
'album-table' => function($sm) //also tried this 'Album\Model\AlbumTable' => function($sm)
{
$dbAdapter = $sm->get('db-adapter');//also tried this $dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$table = new AlbumTable($dbAdapter);
return $table;
},
),
);
}
}
I just wanted to check whether the zf2turorial/album works or not it does throw this error which is similar to this post here in stackoverlow.
The error which it is throwing is:
Additional information:
Zend\ServiceManager\Exception\ServiceNotFoundException
File:
..\vendor\zendframework\zendframework\library\Zend\ServiceManager\ServiceManager.php:392
Message:
Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Album\Model\AlbumTable
I have followed ZF2 Beta 5 tutorial as well, but still encountering this problem. In case if anyone has a solution, please do share with us.
Thanks
seems like somebody has forgotten to update the newest changes in zf2.
the solution:
the file module/Album/Module.php has to contain this content:
<?php
namespace Album;
use Album\Model\AlbumTable;
use Zend\ModuleManager\Feature\ServiceProviderInterface;
class Module implements ServiceProviderInterface
then you have to rename
public function getServiceConfig()
to
public function getServiceConfiguration()
public function getServiceConfiguration() is not the correct function name
rename getServiceConfiguration() to getServiceConfig()
although it is not mandatory you should declare the class Module as
class Module implements ServiceProviderInterface
I am not sure but try to put the code into
config.autoload/global.php: like this way
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=kd_tutorial;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
I have encoutered the same problem when try to implement code follow zend tutorial. The main reason is order-folder
module
ModuleX
config
src
ModuleX //may be you forget this one
Controller
Factory
Model
...
view
Module.php
in Module.php, getConfig(), getAutoloaderConfig() is enough to run
class Module implements AutoloaderProviderInterface, ConfigProviderInterface{
public function getAutoloaderConfig(){
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getConfig(){
return include __DIR__ . '/config/module.config.php';
}
Modify config/autoload/global.php with following code:
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=YourDBName;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
and You should put your database credentials in config/autoload/local.php so that they are not in the git repository (as local.php is ignored):
return array(
'db' => array(
'username' => 'YourDBUsername',
'password' => 'YourDBPassword',
),
);
If you want more details refer link1 or link2
Just got the same issue.
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Cache\Model\UniversityStorage
In my case the problem was, that PHPUnit could not find the key Cache\Model\UniversityStorage in the service manager (registry) because it's being added in the Module class of the Cache module and the Cache module was missing in the PHPUnit config file and was also not being loaded:
/module/Application/test/phpunit.config.php
<?php
return array(
'modules' => array(
'Application',
'Cache', // <- was missing
),
'module_listener_options' => array(
'config_glob_paths' => array(
'../../../config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'module',
'vendor',
),
),
);
I've added the Cache module to the module list. Now it works.
The problem is that within config/autoload/global.php the service is named "Zend\Db\Adapter\Adapter" while within module/Album/Module.php it was searching for "Zend\Db\Adapter" (missing additional \Adapter).
Adding missing "\Adapter" within module/Album/Module.php like this fixed it for me.
'AlbumTableGateway' => function($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
In module/Album/src/Album/Model/Album.php, use instead:
array('name' => 'striptags'),
array('name' => 'stringtrim'),
See the above namespaces created by Zend at vendor/zendframework/zendframework/library/Zend/Filter/FilterPluginManager.php
If you are getting similar error for different modules and the code seems jus right then ADD an entry in composer.json
"Album\": "module/Album/src/"
in autoload and autoload-dev section like this where Album is the name of your Module
"autoload": {
"psr-4": {
"Application\\": "module/Application/src/",
"Album\\": "module/Album/src/"
}
},
"autoload-dev": {
"psr-4": {
"ApplicationTest\\": "module/Application/test/",
"Album\\": "module/Album/src/"
}
},
after this run "composer update" and reload the page. check if error is gone.

Resources