zend framework 2 - Cache config files - php

i'm trying to enable the cache for the config files in zend framework 2 :
the module.config.php ( part of services ) :
'service_manager' => array(
'factories' => array(
'translator' => 'Zend\I18n\Translator\TranslatorServiceFactory',
'navigation' => 'Zend\Navigation\Service\DefaultNavigationFactory',
'doctrine.cache.mycache' => function ($sm) {
$cache = new \Doctrine\Common\Cache\MemcacheCache();
$memcache = new \Memcache();
$memcache->connect('localhost', 11211);
$cache->setMemcache($memcache);
return $cache;
},
),
),
the application.config.php ( part of enabling the cache for config ):
'module_listener_options' => array(
'module_paths' => array(
'./module',
'./vendor',
),
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
'config_cache_enabled' => true,
'config_cache_key' => md5('config'),
'module_map_cache_enabled' => true,
'module_map_cache_key' => md5('module_map'),
'cache_dir' => "./data/cache/modulecache",
),
And here the error i got :
Fatal error: Call to undefined method Closure::__set_state()
Thanks.

Config files can't be cached if they contain anonymous functions (in your case, the value for doctrine.cache.mycache). You will need to move just that part out of the config file and into your Module.php class' getServiceConfig() instead. That should fix the issue.

Related

Doctrine caching configuration

In the doctrine docs, it looks like I need the configuration object available for metadata caching:
<?php
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Configuration;
use Doctrine\Common\Proxy\ProxyFactory;
// ...
if ($applicationMode == "development") {
$cache = new \Doctrine\Common\Cache\ArrayCache;
} else {
$cache = new \Doctrine\Common\Cache\ApcCache;
}
$config = new Configuration;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver('/path/to/lib/MyProject/Entities');
$config->setMetadataDriverImpl($driverImpl);
However, this is currently inside a module in the zend directory in composer, so I cant change it. Id like to hand the option to do this in the array configuration:
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'params' => array(
'pdo' => new PDO("connection details")
),
'query_cache'=>new PhpFileCache(), //<- like this
'metadata_cache'=>new PhpFileCache(), //<- and this
),
),
),
I know this is possible because I have done it once before, however, I cant seem to find this method on the docs anymore. The current docs show the setup for YAML.
I can set up many connections in the Doctrine entity manager, but I supply one configuration since this sets up things that run once for the lifetime of that run, or if we have a cache installed such as APC, the lifetime of that release.
I achieve this by adding the info to $config['doctrine']['configuration'], not $config['doctrine']['orm_default/your_connection']['configuration']
return array(
'doctrine' => array(
'connection' => array(
'orm_default' => array(
'params' => array(
'pdo' => new PDO("connection")
),
),
),
'configuration' => array(
'orm_default' => array(
'metadata_cache' => 'filesystem',
'query_cache' => 'filesystem',
'result_cache' => 'filesystem'
),
),
),

Zend Framework 2 + Doctrine Extensions Taggable

I am trying to integrate DoctrineExtension-Taggable into Zend Framework 2.
First I added to composer:
"anh/doctrine-extensions-taggable": "1.1.*#dev"
Then built instances via service manager (in module.config.php):
'service_manager' => array(
'factories' => array(
'taggableManager' => function($sm) {
$entityManager = $sm->get('Doctrine\ORM\EntityManager');
return new \Anh\Taggable\TaggableManager($entityManager, '\Anh\Taggable\Entity\Tag', '\Anh\Taggable\Entity\Tagging');
},
'taggableSubscriber' => function($sm) {
$taggableManager = $sm->get('taggableManager');
return new \Anh\Taggable\TaggableSubscriber($taggableManager);
},
),
),
Once instances created I registered subscriber in EventManager:
'doctrine' => array(
'driver' => array(
// standart code for driver initialization
),
'eventmanager' => array(
'orm_default' => array(
'subscribers' => array(
'taggableSubscriber',
),
),
),
),
This is all what I did. But at this step I have an error
Fatal error: Uncaught exception
'Zend\ServiceManager\Exception\CircularDependencyFoundException' with
message 'Circular dependency for LazyServiceLoader was found for
instance Doctrine\ORM\EntityManager' in
/var/www/html/fryday/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php
on line 946
What I am doing wrong?

Enable Doctrine 2 cache in a ZF2 project

How to enable cache in a project working with Zend Framework 2 and Doctrine 2? and what cache exactly should be enabled the doctrine cache or the zend cache?
Here what i've tried but can't see any diference in the time execution added in the
module\Application\config\module.config.php
'doctrine.cache.my_memcache' => function ($sm) {
$cache = new \Doctrine\Common\Cache\MemcacheCache();
$memcache = new \Memcache();
$memcache->connect('localhost', 11211);
$cache->setMemcache($memcache);
return $cache;
},
'doctrine.cache.apc' => function ($sm){
$apc = new \Doctrine\Common\Cache\ApcCache();
return $apc;
},
// Doctrine config
'doctrine' => array(
'driver' => array(
__NAMESPACE__ . '_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity'),
),
'orm_default' => array(
'drivers' => array(
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
),
)
),
'configuration' => array(
'orm_defaults' => array(
'metadata_cache' => 'apc',
'query_cache' => 'apc',
'result_cache' => 'my_memcache',
)
)
),
any help or idea or explication is appreciated.
thanks.
To reduce unnecessary headaches, always use array cache on development time and memcached, redis or apc when your application running on production environment.
You should put your factory definitions under the service_manager > factories key, not directly in the module configuration array.
Try this in your module.config.php:
return [
'doctrine' => [
'configuration' => [
'orm_default' => [
'metadata_cache' => 'mycache',
'query_cache' => 'mycache',
'result_cache' => 'mycache',
'hydration_cache' => 'mycache',
]
],
],
'service_manager' => [
'factories' => [
'doctrine.cache.mycache' => function ($sm) {
$cache = new \Doctrine\Common\Cache\MemcacheCache();
$memcache = new \Memcache();
$memcache->connect('localhost', 11211);
$cache->setMemcache($memcache);
return $cache;
},
],
],
];
Also I strongly recommend moving factories to individual factory classes, always. This way, you'll have a more readable, maintainable and efficient application on production environment with the help of merged configuration cache.
For example:
'service_manager' => [
'factories' => [
'doctrine.cache.mycache' => \App\Memcache\Factory::class // implement FactoryInterface
],
],
];
Update for future readers after several years:
I would highly recommend looking into roave/psr-container-doctrine
before writing custom dedicated factories for various doctrine components such as entity manager, config or cache. As a contributor of the library I can say that it serves the purpose nicely for most of the use cases I needed so far. When you really need a specialized factory, you can either extend or compose or decorate factories provided and add your own logic on top it.

please help me Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter

i'm following this tutorial but got error Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for Zend\Db\Adapter\Adapter
i've googling and tried all solution but no luck. please helppppp i'm depressed :|
FYI : i'm using this skeleton https://github.com/zendframework/ZendSkeletonApplication and go. i didn't install zend.
module.php
namespace Album;
// Add these import statements:
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\Tabl`enter code here`eGateway;
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 getServiceConfig()
{
return array(
'factories' => array(
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
}
global.php
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=aaa;host=aaa',
'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 read & tried these :
ZF2 - get was unable to fetch or create an instance for getAlbumTable
ServiceNotFoundException in ZendFramework 2, example from Rob Allen
always end up without clarity
This is because of DB configuration error, to solve this you have to configure DB in global.php in main config folder.Code is given below, Copy paste and Just change the db name and password,
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2tutorial;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
'username' => 'root',
'password' => ''
),
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter'
=> 'Zend\Db\Adapter\AdapterServiceFactory',
),
),
);
The problem is with the following line in your module.php
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
The db configuration information in your global.php can not recognized by your program. As a resolve, you can transfer the configuration you have written on global.php to module.config.php.
My module.config.php is as follows:
<?php
return array(
'controllers' => array(
'invokables' => array(
'Album\Controller\Album' => 'Album\Controller\AlbumController',
),
),
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zend;host=localhost',
'driver_options' => array(
PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES \'UTF8\''
),
),
// The following section is new and should be added to your file
'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 my getServiceConfig() under Module.php is as below:
public function getServiceConfig()
{
return array(
'factories' => array(
'db' => function($sm) {
echo PHP_EOL . "SM db-adapter executed." . PHP_EOL;
$config = $sm->get('config');
$config = $config['db'];
//print_r($config);
//exit();
$dbAdapter = new Adapter($config);
return $dbAdapter;
},
'Album\Model\AlbumTable' => function($sm) {
$tableGateway = $sm->get('AlbumTableGateway');
$table = new AlbumTable($tableGateway);
return $table;
},
'AlbumTableGateway' => function ($sm) {
$dbAdapter = $sm->get('db');
//print_r($dbAdapter);
//exit();
$resultSetPrototype = new ResultSet();
$resultSetPrototype->setArrayObjectPrototype(new Album());
return new TableGateway('album', $dbAdapter, null, $resultSetPrototype);
},
),
);
}
After that everything was working.
Note:
For some reason global.php was not read by Zend2 in my case.(Somebody needs to research further with that I suggest)local.php was still read. So I am still keeping my username and password information in local.php. Hope this will help you to get rid of this uncomfortable error.
This will work if you are getting problem on Ibm I series Server.
The cause of the problem is that IBMi cannot handle relative paths in the config.
I resolved it on my machine with the following
'config_glob_paths' => array( '/www/local/zf2/config/autoload/{,*.}{global,local}.php', ),
ie set 'config_glob_paths' to the full path instead of the relative path in application.config.php.
Note: if you are getting the error on local then pls check configruation file.
I just added the code below in "my_project / config / autoload / global.php" and it worked perfectly.
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
),
I am using Oracle and let "username / password" in "local.php".
Thank you!

Zend Framework 2: Disable module on production environment

OK, here's the problem:
I have a module in my Zend Framework 2 application that I wish to not include on production. Therefore, I made a file inside config/autoload called local.php with the following content:
'modules' => array(
'Application',
'My_Local_Module',
),
while config/application.config.php contains:
'modules' => array(
'Application',
),
When I try to access the module in the URL, a 404 is returned. However, when I set the modules inside the application.config.php file, the module is displayed properly. The environment variable is set to local.
Put the following lines in your index.php:
<?php
// ...
// Get the current environment (development, testing, staging, production, ...)
$env = strtolower(getenv('APPLICATION_ENV'));
// Assume production if environment not defined
if (empty($env)) {
$env = 'production';
}
// Get the default config file
$config = require 'config/application.config.php';
// Check if the environment config file exists and merge it with the default
$env_config_file = 'config/application.' . $env . '.config.php';
if (is_readable($env_config_file)) {
$config = array_merge_recursive($config, require $env_config_file);
}
// Run the application!
Zend\Mvc\Application::init($config)->run();
Then create different configuration files for each environment.
application.config.php:
<?php
return array(
'modules' => array(
'Application'
),
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php'
),
'module_paths' => array(
'./module',
'./vendor'
)
)
);
application.development.config.php:
<?php
return array(
'modules' => array(
'ZendDeveloperTools'
)
);
application.production.config.php:
<?php
return array(
'module_listener_options' => array(
'config_cache_enabled' => true,
'module_map_cache_enabled' => true,
'cache_dir' => 'data/cache/'
)
);
You have to enumerate all your modules inside application.config.php, so the config should look like that:
$modules = array (
'Application'
);
if (IS_LOCAL_DOMAIN)
{
$modules [] = "My_Local_Module";
}
return array(
'modules' => $modules,
'module_listener_options' => array(
'config_glob_paths' => array(
'config/autoload/{,*.}{global,local}.php',
),
'module_paths' => array(
'./module',
'./vendor',
),
),
);

Categories