Hi, everyone!
I'm building a PHP site and I decided to go with Doctrine as DBAL and ORM. I'm a bit rusty on my PHP skills, so please help me understand one thing.
The way to configure Doctrine, as specified in their docs is to execute code like this:
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);
$config->setQueryCacheImpl($cache);
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');
if ($applicationMode == "development") {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
$connectionOptions = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
What I'm puzzled about is how should you execute this code. Is it something you put in a config.php file and include in each of your pages, basically executing this each time a page is processed? Or am I supposed to do this configuration once?
On a related note - please help me understand how setting cache to ArrayCache instead of APC cache helps me during development?
Thanks!
doctrine is a pretty hard choice if your PHP skills are rusty... Anyway...
You can create the connection and eventmanger once in a bootstrap file. Then you can pass the eventmanager instance to your class constructors or make it availably through a static registry (dirty dirty dirty) or ...
This is a good starting point (for orm 2.0):
http://www.doctrine-project.org/docs/orm/2.0/en/tutorials/getting-started-xml-edition.html
The only reason for using ArrayCache in dev mode I can think of is, that you do not have to configure APC at that point and can focus on your coding. In production mode APC gives you the extra boost and is highly recommended.
Regards
Flo
Related
I have now run out of ideas and Google is not helping either. I believe the issue is rather simple to solve, but currently I am not seeing why it happens. Everything works fine on my testing environment with dev mode.
But doesn't work on production where the dev mode is off and proxy files need to be generated manually.
The first time I generated proxy files on the production environment, everything worked fine. Now I needed to improve some of the entities and when I use the "doctrine orm:generate-proxies" command again, then all the proxy files get generated and when I look at the new entity proxy files, then I can see that the new column are mapped.
But when I try to save or load new object, then nothing gets saved or load to the new columns. It is as if doctrine 2 doesn't understand, that there are new proxy files that it should use. Instead, it keeps on using some other hidden old proxy files, cached away in some dark end.
Any idea why doctrine 2 doesn't use the newly generated proxy files?
For extra clarity, this the the Doctrine Initialisation code.
$paths = array(__DIR__ . '/../ORM/Definition/Doctrine2/Entity');
$isDevMode = false;
$autoGenerateProxyClasses = AbstractProxyFactory::AUTOGENERATE_NEVER;
if ($this->serverDevelopment()) {
$isDevMode = true;
$autoGenerateProxyClasses = AbstractProxyFactory::AUTOGENERATE_ALWAYS;
}
$dbParams = array(
'driver' => 'pdo_mysql',
'user' => 'REMOVE',
'password' => 'REMOVE',
'dbname' => 'REMOVE',
'host' => 'REMOVE'
);
$config = Setup::createAnnotationMetadataConfiguration($paths, $isDevMode);
$config->setProxyDir(__DIR__ . '/../ORM/Definition/Doctrine2/Entity/Proxy');
$config->setProxyNamespace('Database\ORM\Definition\Doctrine2\Entity\Proxy');
$config->setAutoGenerateProxyClasses($autoGenerateProxyClasses);
$this->entityManager = EntityManager::create($dbParams, $config);
Any help would be appreciated,
Hendrik
I am using following code to generate proxies:
$em = Zend_Registry::get('em');
$proxyFactory = $em->getProxyFactory();
$metadatas = $em->getMetadataFactory()->getAllMetadata();
$proxyFactory->generateProxyClasses($metadatas, APPLICATION_PATH . '/models/Proxies');
I have Proxies folder inside models folder.
Try generating proxies using this code.
Found out the issue. But I'm not sure, if it was the permissions or the user. But I changed the folder from 775 to 777 and also the user. Now it works :)
I'm re-engineering an application, and I've chosen to use TDD to do it. I'm new to TDD and have yet to fall in love with the process. Currently, I've run into a problem that I'm not able to find any clear help on. I might just be overthinking, but would certainly appreciate some help understanding what I'm running into.
The project I am working on persists to MongoDB. I've been working with Mongo for a while now and like it a lot, but the PHP driver doesn't seem to fit into my limited understanding of how (and what) to test with a fake/mock.
Here is a sample class (I haven't checked to see if it will run):
class UserCollection {
protected $_mongo_client; //connection to persistence layer (MongoDB or mock)
public function __construct($mongo_client, $id = NULL) {
$this->_mongo_client = $mongo_client;
}
public function getUserInfo($mid) {
$collection = $this->_mongo_client->vertical->primaryMember;
$user = $collection->findOne(array('memberId' => intval($mid)), array('memberId'=> true, 'name'=>true,'stats' => true));
if($user['memberId']) {
$return['status'] = "Success";
$return['user'] = $user;
} else {
$return['status'] = "Failure";
$return['message'] = "User not found";
}
return $return;
}
}
As I understand it, if I am to create this writing the tests first, I need to create a fake for the DB - and I have been trying to come up with a mock to inject into the constructor. How do I create a mock that handles lines like:
$collection = $this->_mongo_client->vertical->primaryMember;
I'm hoping that I am just overthinking the issue, and there is an easy or better way to do this. At any rate I would appreciate any links, sage advice, or blunt corrections to my thinking.
Another question here addresses this topic as well.
Phactory provides direct support for mocking MongoDB. Here is a complete example from the creators of Phactory in their guide explaining how to mock MongoDB in PHP.
Edit: The above links are now dead, and Phactory appears to be no-longer maintained. There's a new project called `php-mongomock' that aims to solve this problem:
use Helmich\MongoMock\MockCollection;
$collection = new MockCollection();
$collection->createIndex(['foo' => 1]);
$documentId = $collection->insertOne(['foo' => 'bar'])->insertedId();
$collection->updateOne(['_id' => $documentId], ['$set' => ['foo' => 'baz']]);
For those who might stumble across this later, I found a couple of solutions. In the case referenced above I realized that it is more appropriate to pass MongoCollection's in as dependancies, and those are very easy to mock.
However, as I am using Mockery for my mocking library, there are some options for handling "Demeter chains", like the one I asked specifically about:
$collection = $this->_mongo_client->vertical->primaryMember;
Here is a link to the docs:
http://docs.mockery.io/en/latest/reference/demeter_chains.html
It basically states that you can theoretically mock the chain like this:
$mock = \Mockery::mock('\MongoClient');
$mock->shouldReceive('vertical->primaryMember')->andReturn($mockMongoCollection);
You can return anything that you want, and seems like a pretty workable solution.
I've been looking for an explanation on how to integrate Doctrine 2 and Zend Framework 1.12 (or 1.11, or another --I don't really know whether it matters or not but what I'm using is 1.12). I could find several blog posts and even solved questions right here in Stack Overflow but after read them one and all, I couldn't get to get what I was after: do it in a modular application. So, I'd be very grateful if somebody could give me the keys to achieve this.
Thank you very much!
EDIT:
Thank you guys for your replies but the recent release of ZF2 made me to decide to leave ZF1 in order to take advantage of all new improvements and features. As #KTastrophy said, integrating ZF and Doctrine is quite much easier now (I'd even dare to say that everything is easier and more consistent with ZF2). Thank you one more time!
It's easy to integrate doctrine 2 with ZF using the doctrine PEAR installation. After installing you just need to put this in your bootstrap:
protected function _initDoctrine() {
require_once "Doctrine/ORM/Tools/Setup.php";
\Doctrine\ORM\Tools\Setup::registerAutoloadPEAR();
$options = $this->getOptions();
$loader = new \Doctrine\Common\ClassLoader('YourNamespace', realpath(APPLICATION_PATH . "/../library"));
$loader->register();
$isDevMode = (APPLICATION_ENV == 'production') ? false: true;
$entityManager = \Doctrine\ORM\EntityManager::create(
$options['doctrine']['dbal'],
\Doctrine\ORM\Tools\Setup::createYAMLMetadataConfiguration(array(
realpath(APPLICATION_PATH."/../library/YourNamespace/Yaml"),
), $isDevMode)
);
Zend_Registry::set('entityManager', $entityManager);
return $entityManager;
}
The $this->getOptions() retrieves the database name, user and password from the config file.
If you take this tutorial as an example
http://christian.soronellas.es/2010/12/19/zend-framework-and-doctrine-2/?lang=en
See this part of the configuration code
$config = new Configuration();
$config -> setMetadataCacheImpl($cache);
$driverImpl = $config -> newDefaultAnnotationDriver($options['entitiesPath']);
$config -> setMetadataDriverImpl($driverImpl);
$config -> setQueryCacheImpl($cache);
$config -> setProxyDir($options['proxiesPath']);
$config -> setProxyNamespace('Application\Models\Proxies');
$config -> setAutoGenerateProxyClasses(('development' == APPLICATION_ENV));
$em = EntityManager::create( $this -> _buildConnectionOptions($options), $config );
The function newDefaultAnnotationDriver actually takes an array of entitites path. This creates the opportunity for you to get creative. When I found out about this, I simply created an entity folder in each module and pass each path along the newDefaultAnnotationDriver parameter in an array. Ofcourse by doing this, you will need to set the namespace per module.
I use Bisna
You should apply this patch https://github.com/guilhermeblanco/ZendFramework1-Doctrine2/pull/45
And that works well for me.
In the controller I have this function for retrieve the Entity Manager
/**
* Retrieve the Doctrine Container.
*
* #return Doctrine\ORM\EntityManager
*/
public function getEntityManager()
{
return $this->getInvokeArg('bootstrap')->getResource('doctrine')->getEntityManager();
}
I'm trying to understand the difference between regular Memcache and Doctrine's MemcacheCache.
In my bootstrap I instantiate Memcache like this:
$memcache = new Memcache;
$memcache->connect('localhost', 11211);
\Zend_Registry::set("pdc_memcache_core", $memcache);
I then have the following code for instantiating Doctrine - this is not the full code as I'm just looking at the cachine:
$doctrineConfig = new \Doctrine\ORM\Configuration();
$memcacheCore = \Zend_Registry::get("pdc_memcache_core");
$cache = new \Doctrine\Common\Cache\MemcacheCache;
$cache->setMemcache($memcacheCore);
$cache->setNamespace("PDC_");
\Zend_Registry::set("pdc_memcache", $cache);
$doctrineConfig->setMetadataCacheImpl($cache);
$doctrineConfig->setQueryCacheImpl($cache);
I then access the cache like this:
if (\Zend_Registry::get("pdc_memcache")->contains($cacheKey)) {
...
}
I'm not trying to store Doctrine entities in Memcache - I'm just storing strings and serialised arrays.
Now... is this the correct way to use Memcache with Doctrine? I can see that you use setMemcache to assign the Memcache instance to Doctrine's MemcacheCache... but would I use MemcacheCache for my own stuff? Or should I use the Memcache instance directly?
Would really appreciate some thoughts on this, as I'm confused by how this is supposed to link together.
It is perfectly ok to use the Memcache Cache of Doctrine Common, thats also the correct way and you also have some abstraction that allows you to consume any Doctrine\Common\Cache\Cache instance. I'm not quite sure you would need that anyway, as you're working with Zend Framework, and you probably could use the CacheManager or it's associated CacheManager resource, which both would give you the advantage to make your caching mechanism configurable.
I would like to integrate Doctrine 2 ORM into WordPress for use in the plugins I'm developing. There is currently a plugin that offers Doctrine 1.2.3 ORM support in WordPress, but not v2.
The biggest problem I'm having is that I don't understand how Doctrine 2 ORM interacts with my code; specifically, what their configuration code provides me with and where I should go from here:
// 3.1.1
require dirname( __FILE__ ) . '/lib/Doctrine/ORM/Tools/Setup.php';
$lib = dirname( __FILE__ ) . '/lib';
Doctrine\ORM\Tools\Setup::registerAutoloadDirectory($lib);
// 3.1.2
use Doctrine\ORM\EntityManager,
Doctrine\ORM\Configuration;
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);
$config->setQueryCacheImpl($cache);
$config->setProxyDir('/path/to/myproject/lib/MyProject/Proxies');
$config->setProxyNamespace('MyProject\Proxies');
if ($applicationMode == "development") {
$config->setAutoGenerateProxyClasses(true);
} else {
$config->setAutoGenerateProxyClasses(false);
}
$connectionOptions = array(
'driver' => 'pdo_sqlite',
'path' => 'database.sqlite'
);
$em = EntityManager::create($connectionOptions, $config);
I had continued reading through sections of the documentation up to section 8 and have some understanding. My questions are:
Is this configuration enough to allow me to work with Doctrine 2 ORM in my plugins?
Are there any other key steps I'm missing before working with Doctrine 2 ORM? The WordPress plugin seems to automatically generate all of the appropriate classes from the database. I read the documentation a few times, but I feel like I'm missing some big step... or maybe Doctrine 2 ORM is just that much different?
Is the EntityManager some global variable that I can use throughout my entities?
I assume I have to link everything together, #Entity in a file is not enough for Doctrine to know where the entity is. Is there somewhere in the documentation that defines this?
If anyone can provide a quick rundown of how it all works together: configuration, entities, etc. Or provide any clear cut tutorials that may already be out there, I would really appreciate it.
IMHO you shouldn't use Doctrine2 with WP
Doctrine 2 is more appropriate solution for site with huge business logic and I believe you don't use WP for this purposes
Doctrine 2 has huge code base (~11MB) which add overhead for classloading and processing of requests
Doctrine 2 use a lot of memory with default hydration mode (object)
Building custom sql is much harder with Doctrine.