Enable Doctrine 2 cache in a ZF2 project - php

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.

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'
),
),
),

zf2 - Unable to resolve service Zend\Db\Adapter\Adapter to a factory

Why i'm getting this error even i have added all the classes already?
Unable to resolve service "Zend\Db\Adapter\Adapter" to a factory; are
you certain you provided it during configuration?
Here is my Module.php:
namespace Album;
use Album\Model\Album;
use Album\Model\AlbumTable;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\TableGateway\TableGateway;
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 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);
},
),
);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
}
UPDATED:
FILES - application.config.php:
return [
// Retrieve list of modules used in this application.
'modules' => [
'Zend\Router',
'Zend\Validator',
'Application',
'Album',
'Blog',
],
// These are various options for the listeners attached to the ModuleManager
'module_listener_options' => [
'module_paths' => [
'./module',
'./vendor',
],
'config_glob_paths' => [
// realpath(__DIR__) . '/autoload/{{,*.}global,{,*.}local}.php',
realpath(__DIR__) . '/autoload/{,*.}{global,local}.php',
],
'config_cache_enabled' => false,
// The key used to create the configuration cache file name.
'config_cache_key' => 'application.config.cache',
'module_map_cache_enabled' => false,
// The key used to create the class map cache file name.
'module_map_cache_key' => 'application.module.cache',
// The path in which to cache merged configuration.
'cache_dir' => 'data/cache/',
// 'check_dependencies' => true,
],
];
You may have missed a step from the tutorial you are following.
in config/autoload/global.php add:
return array(
'db' => array(
'driver' => 'Pdo',
'dsn' => 'mysql:dbname=zf2tutorial;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',
),
),
);
Probaly because the $sm->get('Zend\Db\Adapter\Adapter') is not a service but is a class to set up an Adapter and is not registered within the ServiceManager yet.
Create a factory which builds the Adapter class for you by injecting the Config into it. Then register this AdapterFactory, which returns your adapter, within your serviceConfig. Or you could use the default AdapterFactory of Zend, which uses the 'db' key within your configuration to setup the database adapter.
Registering the Adapter within your Application Module.php:
public function getServiceConfig()
{
return [
'factories' => [
\Zend\Db\Adapter\Adapter::class => \Zend\Db\Adapter\AdapterServiceFactory::class,
]
// rest of your configuration
];
}
See the documentation of ZF2 v2.4 - Setting up a database adapter

zend framework 2 - Cache config files

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.

How to store queries and their results in memcache using cache enabled for doctrine 2 (using zend framework 2 )?

I guess all is in the title , I've looked a lot for a solution but can't figure out how to do it ? Here is my configuration for memcache in module.config.php :
// Doctrine config
'doctrine' => array(
'driver' => array(
__NAMESPACE__ . '_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'paths' => array(__DIR__ . '/../src/' . __NAMESPACE__ . '/Entity')
),
'orm_default' => array(
'drivers' => array(
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
),
)
),
/***** enabling the memcache ****/
'configuration' => array(
'orm_default' => array(
'metadata_cache' => 'mycache',
'query_cache' => 'mycache',
'result_cache' => 'mycache',
)
/**** end ****/
)
),
'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;
},
),
),
i'm using zend framework 2 and doctrine 2 .
thanks.
If everything is configured correctly you don't need to configure anything else for Query Cache and Metadata Cache to work, however, to enable Result Cache you will have to call useResultCache explicitly on each query.
Example:
<?php
$query = $em->createQuery('select u from \Entities\User u');
$query->useResultCache(true);

How to configure Doctrine file mapping driver in ZF2

I have this error:
Fatal error: Uncaught exception
'Doctrine\Common\Persistence\Mapping\MappingException' with message
'File mapping drivers must have a valid directory path, however the
given path [path/to/my/entities] seems to be incorrect
and i have this in my module.config.php:
'doctrine' => array(
'driver' => array(
// defines an annotation driver with two paths, and names it `my_annotation_driver`
'my_annotation_driver' => array(
'class' => 'Doctrine\ORM\Mapping\Driver\AnnotationDriver',
'cache' => 'array',
'paths' => array(
__DIR__ . '/../src/Realez/Entity',
'another/path'
),
),
// default metadata driver, aggregates all other drivers into a single one.
// Override `orm_default` only if you know what you're doing
'orm_default' => array(
'drivers' => array(
// register `my_annotation_driver` for any entity under namespace `My\Namespace`
'Realez/Entity' => 'my_annotation_driver'
)
)
)
)
I had exactly the same problem. I solved it by creating an empty Entity directory in the location where doctrine expect me to store my entities. All you have to do is create in following location an empty Entity directory: __DIR__ . '/../src/Realez/Entity'.
Modify your module.config.php file.
return array(
'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'
),
),
),
),
);
**File mapping drivers must have a valid directory path, however the given path [path/to/my/entities]**
this mean you don't have an Entity folder at that directory
You just need to create one at that location
Ensure your paths are correct.
__NAMESPACE__ . '_driver' => [
'class' => AnnotationDriver::class,
'cache' => 'array',
'paths' => [__DIR__ . '/../src/Entity/'],
// or: 'paths' => [__DIR__ . '/../src/Entity/'.__NAMESPACE__.'/Entity']
],
'orm_default' => [
'drivers' => [
__NAMESPACE__ . '\Entity' => __NAMESPACE__ . '_driver'
]
],
Also you may try clearing metadata cache with doctrine command line tool:
./doctrine-module orm:clear-cache:metadata

Categories