Hello i am new to this framework and i am getting this error when following the tutorial.
Fatal error: Uncaught exception 'Zend\ModuleManager\Exception\RuntimeException' with message 'Module (Album) could not be initialized.' in C:\website\zend\vendor\ZF2\library\Zend\ModuleManager\ModuleManager.php on line 175
here is the code that i believe there is a mistake
<?php
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'Album', // <-- Add this line to make new module available
),
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => array(
// This should be an array of paths in which modules reside.
// If a string key is provided, the listener will consider that a module
// namespace, the value of that key the specific path to that module's
// Module class.
'module_paths' => array(
'./module',
'./vendor',
),
// An array of paths from which to glob configuration files after
// modules are loaded. These effectively override configuration
// provided by modules themselves. Paths may use GLOB_BRACE notation.
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
// Whether or not to enable a configuration cache.
// If enabled, the merged configuration will be cached and used in
// subsequent requests.
//'config_cache_enabled' => $booleanValue,
// The key used to create the configuration cache file name.
//'config_cache_key' => $stringKey,
// Whether or not to enable a module class map cache.
// If enabled, creates a module class map cache which will be used
// by in future requests, to reduce the autoloading process.
//'module_map_cache_enabled' => $booleanValue,
// The key used to create the class map cache file name.
//'module_map_cache_key' => $stringKey,
// The path in which to cache merged configuration.
//'cache_dir' => $stringPath,
// Whether or not to enable modules dependency checking.
// Enabled by default, prevents usage of modules that depend on other modules
// that weren't loaded.
// 'check_dependencies' => true,
),
// Used to create an own service manager. May contain one or more child arrays.
//'service_listener_options' => array(
// array(
// 'service_manager' => $stringServiceManagerName,
// 'config_key' => $stringConfigKey,
// 'interface' => $stringOptionalInterface,
// 'method' => $stringRequiredMethodName,
// ),
// )
// Initial configuration with which to seed the ServiceManager.
// Should be compatible with Zend\ServiceManager\Config.
// 'service_manager' => array(),
);
Like #foozy said, if you can post more of the code, that would be a big help. It could be a number of things, such as the name you've specified in module.config.php is different from the Module directory or namespace, or a variety of things.
Related
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial\public\index.php:
<?php
/**
* This makes our life easier when dealing with paths. Everything is relative
* to the application root now.
*/
chdir(dirname(__DIR__));
// Decline static file requests back to the PHP built-in webserver
if (php_sapi_name() === 'cli-server' && is_file(__DIR__ . parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH))) {
return false;
}
// Setup autoloading
require 'init_autoloader.php';
// Run the application!
Zend\Mvc\Application::init(require 'config/application.config.php')->run();
If I place a file in the same directory called console.php:
<?php
echo __DIR___
?>
and run:
php console.php
The output is:
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial\public
Clearly this seems to be the wrong directory as 'init_autoloader.php' is actually located here:
C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial
Also my book says that the line:
Zend\Mvc\Application::init(require 'config/application.config.php')->run();
calls the bootstrap() method of the Zend\Mvc\Application. I'm not sure how a call to init() translates to a call to bootstrap() could someone please explain this to me?
My book also says that the call to init takes care of instantiating a new ServiceManager object although I'm not sure how because I see nothing in the bootstrap method of the Application model that has anything to do at all with ServiceManager. Could someone explain this to me?
Thank you for posting...
For reference zf2-tutorial/Module/Application/Module.php
<?php
/**
* Zend Framework (http://framework.zend.com/)
*
* #link http://github.com/zendframework/ZendSkeletonApplication for the canonical source repository
* #copyright Copyright (c) 2005-2014 Zend Technologies USA Inc. (http://www.zend.com)
* #license http://framework.zend.com/license/new-bsd New BSD License
*/
namespace Application;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
}
Clearly this seems to be the wrong directory as 'init_autoloader.php' is actually located here: C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial
The output from your console.php is different because in index.php you'll see this line ...
chdir(dirname(__DIR__));
This effectiveley changes up one directory to C:\Program Files (x86)\Zend\Apache2\htdocs\zf2-tutorial which is the root of the application and the same folder in which init_autoloader.php is located.
Also my book says that the line: Zend\Mvc\Application::init(require 'config/application.config.php')->run(); calls the bootstrap() method of the Zend\Mvc\Application.
You are confusing the Zend\Mvc\Application with the skeleton application module named Application. They are not the same thing.
The bootstrapping being referred to by your book is happening here in the code ...
https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Application.php#L247-L261
As you can see it's a static method, which instantiates the ServiceManager and proceeds to set up services before finally bootstrapping the application here ...
https://github.com/zendframework/zf2/blob/master/library/Zend/Mvc/Application.php#L136-L158
For further reading I'd suggest familiarizing yourself with the MVC layer by reading the docs here
http://framework.zend.com/manual/2.3/en/modules/zend.mvc.intro.html
One can use a value, type or factory for registering an object. I have tried to find simple examples how and when to use each of a registering types, but not succeed.
It would be wonderful, if someone could give brief examples and explain the typical use cases.
Here are some links about the subject:
https://stackoverflow.com/a/21245335/2777805
http://victorsavkin.com/post/72452331552/angulardart-for-angularjs-developers-introduction-to
type
// old syntax
type(SomeType); // or
type(SomeInterface, implementedBy: SomType)
// new syntax
bind(SomeType); // or
bind(SomeInterface, toImplementation: SomType)
default, DI creates an instance and all constructor parameters (if any are resolved by DI and provided)
value
// created inline or e.g. passed in from somewhere as a parameter
// old syntax
value(new SomeType('xxx', 123));
// new syntax
bind(SomeType, toValue: new SomeType('xxx', 123));
if you want to to pass a previously instantiated instance.
I usually use this for configuration settings.
factory
// old syntax
factory(NgRoutingUsePushState,
(_) => new NgRoutingUsePushState.value(false));
// or
factory(UsersRepository, (Injector inj) => new UsersRepository(inj.get(Http)));
// new syntax
bind(NgRoutingUsePushState,toFactory:
(_) => new NgRoutingUsePushState.value(false));
bind(UsersRepository, toFactory: (Injector inj) => new UsersRepository(inj.get(Http)));
(from http://victorsavkin.com/post/72452331552/angulardart-for-angularjs-developers-introduction-to)
when you want DI to delegate the instantiation to a factory function
I have an application with some modules. One of them is CourseSearch. Now I want to add a further one, the SportsPartnerSearch. Since these two modules are very similar to each other, I simply "cloned" / copied the CourseSearch and replaced all "Course" with "SportsPartner" (in all variations: $course to $sportsPartner, course-...phtml to sports-partner-...phtml etc.), in order to edit the logic in the second step. Now I'm getting following errors:
Warning:
require_once(/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php):
failed to open stream: No such file or directory in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Fatal error: require_once(): Failed opening required
'/path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php'
(include_path='.:/usr/share/php:/usr/share/pear') in
/path/to/project/vendor/zendframework/zendframework/library/Zend/Loader/ClassMapAutoloader.php
on line 140
Why is the path to the file being built in such strange way: /path/to/project/module/SportsPartnerSearch//src/CourseSearch/View/Helper/CourseSearchForm.php? Where did I do a mistake?
Some additional information.
The class, that cannot be found because the wron path is CourseSearch\View\Helper\CourseSearchForm in the CourseSearch module. It can be found, when I deactivate the new module SportsPartnerSearch, that contains the class SportsPartnerSearch\View\Helper\SportsPartnerSearchForm.
The CourseSearchForm view helper is instanciated in the CourseSearchForm\Module
class Module {
public function getViewHelperConfig() {
return array(
'factories' => array(
'courseSearchForm' => function($serviceManager) {
$helper = new View\Helper\CourseSearchForm(array('render' => true, 'redirect' => false));
// ERROR. This code is not executed anymore.
$helper->setViewTemplate('course-search/course-search/course-search-form');
$courseSearchForm = $serviceManager->getServiceLocator()->get('CourseSearch\Form\CourseSearchForm');
$helper->setCourseSearchForm($courseSearchForm);
return $helper;
}
)
);
}
}
And called in the layout file:
echo $this->courseSearchForm();
The SportsPartnerSearch\View\Helper\SportsPartnerSearchForm is instanciated in the same way in the SportsPartnerSearch\Module#getViewHelperConfig() and is not called yet.
Have you generated a classmap? Check the autoload_classmap.php file in both the CourseSearch and the SportsPartnerSearch modules. I guess you still have an old classmap lying around. I think the problem is hidden inside the classmap because of the error in the ClassMapAutoloader from Zend, and not the standard autoloader.
You can generate a new classmap with the classmap generator provided in ZF2 (assuming you load it via Composer) with:
cd module/SportsPartnerSearch
../../vendor/bin/classmap_generator.php
This will generate a new classmap file inside the SportsPartnerSearch module.
How to load namespace for all modules (global autoload for whole application)
So far I need to add this to each module:
public function getAutoloaderConfig()
{
return array(
/* ... */
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
/* ... */
'MyNameSpace' => __DIR__ . '/../../library/MyNameSpace',
),
),
);
}
how can I implement this functionality in application.config.php? (i just want to load some base classes for whole application)
To load the modules you need use the file /config/application.config.php
Add the list of your modules to the array under module key.
return array(
// This should be an array of module namespaces used in the application.
'modules' => array(
'Application',
'Pages',
'ModuleName',
),
// ..... rest of array
)
The function getAutoloaderConfig() and getConfig() are used to load the configuration of the module (module internal configuration).
http://framework.zend.com/manual/2.0/en/user-guide/modules.html
autoload that path in your index.php, i.e.,
set_include_path(get_include_path() . PATH_SEPARATOR . __DIR__ . '/../../library/MyNameSpace');
spl_autoload_register(function ($class) {
if(!class_exists($class)) {
$class = str_replace('\\', '/', $class) . '.php';
require_once($class);
}
});
I don't think that you can (or should) do this in the application.config.php file. The whole point behind modules in the ZF2 framework is to separate logic into reusable, independent bits of code. As such, each module maintains and manages its own configuration, including autoloading, independent of the main application or other modules. These settings can often be overridden with the .global.php and .local.php files of the main autoload/ directory, but the autoloading should be left to each individual module.
If the modules you're trying to include are custom pieces of code that you have developed, then perhaps you might want to look at whether they are actually modules at all, or simply code that belongs in the Application module.
How do I specify which implementation of an interface a specific class needs for setter injection?
I have a working eg for constructor injection but not for setters.
class Lister1 {
public $finder;
public function setFinder(Finder $finder){
$this->finder = $finder;
}
}
interface Finder {
public function findAllByName($name);
}
class FinderImpl1 implements Finder {
public function findAllByName($name) {}
}
Now for the above the following code works.
$di = new Di();
$di->instanceManager()->addTypePreference(
'Finder',
'FinderImpl1'
);
$lister = $di->get('Lister1');
But what if I have the following as well
class Lister2 extends Lister1{
}
class FinderImpl2 implements Finder {
public function findAllByName($name) {//assume a different impl}
}
So Lister1 needs FinderImpl1 injected & Lister2 needs FinderImpl2 injected.
Can we add a type preference on a per-class basis?
I had a look at the unit tests that ship with zf2 and nothing leaped out.
It looks like you've found Ralph's DI examples. Good. That was going to be my first suggestion. :)
I may be wrong (been a while since I used DI), but it might be simpler than you are thinking.
Using setter injection like so:
$di = new Zend\Di\Di;
$di->configure(new Zend\Di\Config(array(
'instance' => array(
'Lister1' => array(
'parameters' => array(
'finder' => 'FinderImpl1',
),
),
'Lister2' => array(
'parameters' => array(
'finder' => 'FinderImpl2',
),
),
)
)));
If you were going to define an instance of an interface, then you would need to worry about setting a "preference"; in which case if you had something tricky, you might consider using some aliases along with the preference definition.