├── .gitignore
├── tests
├── bootstrap.php
├── Mapping
│ └── PageMapping.php
├── Document
│ └── Page.php
├── Driver
│ └── ClassMapDriverTest.php
└── Provider
│ └── DoctrineMongoDbOdmProviderTest.php
├── .travis.yml
├── src
├── Driver
│ ├── OdmMappingInterface.php
│ └── ClassMapDriver.php
└── Provider
│ └── DoctrineMongoDbOdmProvider.php
├── phpunit.xml.dist
├── composer.json
├── LICENSE
└── README.md
/.gitignore:
--------------------------------------------------------------------------------
1 | composer.lock
2 | /cache
3 | /vendor
4 |
5 | .idea
--------------------------------------------------------------------------------
/tests/bootstrap.php:
--------------------------------------------------------------------------------
1 | setPsr4('Saxulum\Tests\DoctrineMongoDbOdm\\', __DIR__);
5 |
6 | \Doctrine\Common\Annotations\AnnotationRegistry::registerLoader([$loader, 'loadClass']);
7 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | services: mongodb
4 |
5 | php:
6 | - 5.6
7 | - 7.0
8 | - 7.1
9 |
10 | before_script:
11 | - echo 'extension=mongodb.so' >> ~/.phpenv/versions/$(phpenv version-name)/etc/php.ini
12 | - composer --prefer-source install
13 |
14 | script: phpunit --coverage-text --verbose
15 |
--------------------------------------------------------------------------------
/src/Driver/OdmMappingInterface.php:
--------------------------------------------------------------------------------
1 |
2 |
13 |
14 |
15 | ./tests
16 |
17 |
18 |
19 |
20 | ./src
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/tests/Mapping/PageMapping.php:
--------------------------------------------------------------------------------
1 | setCollection('page');
16 |
17 | $metadata->mapField([
18 | 'fieldName' => 'id',
19 | 'type' => 'string',
20 | 'id' => true,
21 | ]);
22 |
23 | $metadata->mapField([
24 | 'fieldName' => 'title',
25 | 'type' => 'string',
26 | ]);
27 |
28 | $metadata->mapField([
29 | 'fieldName' => 'body',
30 | 'type' => 'string',
31 | ]);
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "saxulum/saxulum-doctrine-mongodb-odm-provider",
3 | "description": "Saxulum Doctrine MongoDB ODM Provider",
4 | "keywords": ["saxulum", "pimple", "cilex", "silex", "doctrine", "mongo", "mongodb", "odm"],
5 | "license": "MIT",
6 | "authors": [
7 | {
8 | "name": "Dominik Zogg",
9 | "email": "dominik.zogg@gmail.com"
10 | }
11 | ],
12 | "require": {
13 | "php": "~7.0|~5.6",
14 | "alcaeus/mongo-php-adapter": "^1.1.3",
15 | "doctrine/mongodb-odm": "~1.0",
16 | "pimple/pimple": ">=2.1,<4",
17 | "saxulum/saxulum-doctrine-mongodb-provider": "~2.0"
18 | },
19 | "require-dev": {
20 | "phpunit/phpunit": "~5.7"
21 | },
22 | "provide": {
23 | "ext-mongo": "1.6.14"
24 | },
25 | "suggest": {
26 | "dflydev/psr0-resource-locator-service-provider": "1.0.*@dev"
27 | },
28 | "autoload": {
29 | "psr-4": { "Saxulum\\DoctrineMongoDbOdm\\": "src/" }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (c) 2013 Dominik Zogg
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy
4 | of this software and associated documentation files (the "Software"), to deal
5 | in the Software without restriction, including without limitation the rights
6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 | copies of the Software, and to permit persons to whom the Software is furnished
8 | to do so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19 | THE SOFTWARE.
--------------------------------------------------------------------------------
/tests/Document/Page.php:
--------------------------------------------------------------------------------
1 | id;
36 | }
37 |
38 | /**
39 | * @param $title
40 | *
41 | * @return $this
42 | */
43 | public function setTitle($title)
44 | {
45 | $this->title = $title;
46 |
47 | return $this;
48 | }
49 |
50 | /**
51 | * @return string
52 | */
53 | public function getTitle()
54 | {
55 | return $this->title;
56 | }
57 |
58 | /**
59 | * @param $body
60 | *
61 | * @return $this
62 | */
63 | public function setBody($body)
64 | {
65 | $this->body = $body;
66 |
67 | return $this;
68 | }
69 |
70 | /**
71 | * @return string
72 | */
73 | public function getBody()
74 | {
75 | return $this->body;
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/tests/Driver/ClassMapDriverTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder(ClassMetadata::class)
17 | ->disableOriginalConstructor()
18 | ->setMethods(['setCollection', 'mapField'])
19 | ->getMock();
20 |
21 | $classMetadata
22 | ->expects(self::once())
23 | ->method('setCollection')
24 | ->with('page');
25 |
26 | $classMetadata
27 | ->expects(self::at(1))
28 | ->method('mapField')
29 | ->with([
30 | 'fieldName' => 'id',
31 | 'type' => 'string',
32 | 'id' => true,
33 | ]);
34 |
35 | $classMetadata
36 | ->expects(self::at(2))
37 | ->method('mapField')
38 | ->with([
39 | 'fieldName' => 'title',
40 | 'type' => 'string',
41 | ]);
42 |
43 | $classMetadata
44 | ->expects(self::at(3))
45 | ->method('mapField')
46 | ->with([
47 | 'fieldName' => 'body',
48 | 'type' => 'string',
49 | ]);
50 |
51 | $driver = new ClassMapDriver($this->getClassMap());
52 |
53 | $driver->loadMetadataForClass(Page::class, $classMetadata);
54 | }
55 |
56 | public function testGetAllClassNamesReturnsTheClassMap()
57 | {
58 | $classMap = $this->getClassMap();
59 |
60 | $driver = new ClassMapDriver($classMap);
61 |
62 | self::assertEquals(array_keys($classMap), $driver->getAllClassNames());
63 | }
64 |
65 | private function getClassMap()
66 | {
67 | return [Page::class => PageMapping::class];
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/src/Driver/ClassMapDriver.php:
--------------------------------------------------------------------------------
1 | classMap = $classMap;
23 | }
24 |
25 | /**
26 | * Loads the metadata for the specified class into the provided container.
27 | *
28 | * @param string $className
29 | * @param ClassMetadata $metadata
30 | * @throws MappingException
31 | */
32 | public function loadMetadataForClass($className, ClassMetadata $metadata)
33 | {
34 | if (false === $metadata instanceof OdmClassMetadata) {
35 | throw new MappingException(
36 | sprintf('Metadata is of class "%s" instead of "%s"', get_class($metadata), OdmClassMetadata::class)
37 | );
38 | }
39 |
40 | if (false === isset($this->classMap[$className])) {
41 | throw new MappingException(
42 | sprintf('No configured mapping for document "%s"', $className)
43 | );
44 | }
45 |
46 | $mappingClassName = $this->classMap[$className];
47 |
48 | if (false === ($mapping = new $mappingClassName()) instanceof OdmMappingInterface) {
49 | throw new MappingException('Class %s does not implement the OdmMappingInterface');
50 | }
51 |
52 | /* @var OdmMappingInterface $mapping */
53 | /* @var OdmClassMetadata $metadata */
54 |
55 | $mapping->configureMapping($metadata);
56 | }
57 |
58 | /**
59 | * Gets the names of all mapped classes known to this driver.
60 | *
61 | * @return array the names of all mapped classes known to this driver
62 | */
63 | public function getAllClassNames()
64 | {
65 | return array_keys($this->classMap);
66 | }
67 |
68 | /**
69 | * Returns whether the class with the specified name should have its metadata loaded.
70 | * This is only the case if it is either mapped as an Entity or a MappedSuperclass.
71 | *
72 | * @param string $className
73 | *
74 | * @return bool
75 | */
76 | public function isTransient($className)
77 | {
78 | if (isset($this->classMap[$className])) {
79 | return false;
80 | }
81 |
82 | return true;
83 | }
84 | }
85 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | saxulum-doctrine-mongodb-odm-provider
2 | =====================================
3 |
4 | **works with plain silex-php**
5 |
6 | [](https://travis-ci.org/saxulum/saxulum-doctrine-mongodb-odm-provider)
7 | [](https://packagist.org/packages/saxulum/saxulum-doctrine-mongodb-odm-provider)
8 | [](https://packagist.org/packages/saxulum/saxulum-doctrine-mongodb-odm-provider)
9 |
10 | Provides Doctrine MongoDB ODM Document Managers as services to Pimple applications.
11 |
12 | Features
13 | --------
14 |
15 | * Default Document Manager can be bound to any database connection
16 | * Multiple Document Managers can be defined
17 | * Mechanism for allowing Service Providers to register their own
18 | mappings
19 |
20 |
21 | Requirements
22 | ------------
23 |
24 | * PHP 5.3+
25 | * Doctrine MongoDB ODM ~1.0
26 |
27 |
28 | Installation
29 | ------------
30 |
31 | Through [Composer](http://getcomposer.org) as [saxulum/saxulum-doctrine-mongodb-odm-provider][4].
32 |
33 |
34 | Usage
35 | -----
36 |
37 | To get up and running, register `DoctrineMongoDbOdmProvider` and
38 | manually specify the directory that will contain the proxies along
39 | with at least one mapping.
40 |
41 | In each of these examples an Document Manager that is bound to the
42 | default database connection will be provided. It will be accessible
43 | via **mongodbodm.dm**.
44 |
45 | ```php
46 | register(new DoctrineMongoDbProvider, [
64 | "mongodb.options" => [
65 | "server" => "mongodb://localhost:27017",
66 | "options" => [
67 | "username" => "root",
68 | "password" => "root",
69 | "db" => "admin"
70 | ],
71 | ],
72 | ]);
73 |
74 | $app->register(new DoctrineMongoDbOdmProvider, [
75 | "mongodbodm.proxies_dir" => "/path/to/proxies",
76 | "mongodbodm.hydrator_dir" => "/path/to/hydrator",
77 | "mongodbodm.dm.options" => [
78 | "database" => "test",
79 | "mappings" => [
80 | // Using actual filesystem paths
81 | [
82 | "type" => "annotation",
83 | "namespace" => "Foo\Entities",
84 | "path" => __DIR__."/src/Foo/Entities",
85 | ],
86 | [
87 | "type" => "xml",
88 | "namespace" => "Bat\Entities",
89 | "path" => __DIR__."/src/Bat/Resources/mappings",
90 | ],
91 | [
92 | 'type' => 'class_map',
93 | 'namespace' => 'Bar\Entities',
94 | 'map' => [
95 | 'Bar\Entities\Bar' => 'Sample\Mapping\Bar'
96 | ]
97 | ]
98 | ],
99 | ],
100 | ]);
101 | ```
102 |
103 |
104 | Configuration
105 | -------------
106 |
107 | ### Parameters
108 |
109 | * **mongodbodm.dm.options**:
110 | Array of Document Manager options.
111 |
112 | These options are available:
113 | * **connection** (Default: default):
114 | String defining which database connection to use. Used when using
115 | named databases via **mongodbs**.
116 | * **database**
117 | The database which should be uses
118 | * **mappings**:
119 | Array of mapping definitions.
120 |
121 | Each mapping definition should be an array with the following
122 | options:
123 | * **type**: Mapping driver type, one of `annotation`, `xml`, `yml`, `simple_xml`, `simple_yml`, `php`
124 | or `class_map`.
125 | * **namespace**: Namespace in which the entities reside.
126 |
127 | Additionally, each mapping definition should contain one of the
128 | following options:
129 | * **path**: Path to where the mapping files are located. This should
130 | be an actual filesystem path. For the php driver it can be an array
131 | of paths
132 | * **resources_namespace**: A namespaceish path to where the mapping
133 | files are located. Example: `Path\To\Foo\Resources\mappings`
134 |
135 | Each mapping definition can have the following optional options:
136 | * **alias** (Default: null): Set the alias for the document namespace.
137 |
138 | Each **annotation** mapping may also specify the following options:
139 | * **use_simple_annotation_reader** (Default: true):
140 | If `true`, only simple notations like `@Document` will work.
141 | If `false`, more advanced notations and aliasing via `use` will
142 | work. (Example: `use Doctrine\ODM\MongoDB\Mapping AS ODM`, `@ODM\Document`)
143 | Note that if set to `false`, the `AnnotationRegistry` will probably
144 | need to be configured correctly so that it can load your Annotations
145 | classes. See this FAQ:
146 | [Why aren't my Annotations classes being found?](#why-arent-my-annotations-classes-being-found)
147 |
148 | Each **php** mapping may also specify the following options:
149 | * **static** (Default: true):
150 | If `true`, the static php driver will be used, which means each document needs to add:
151 | public static function loadMetadata(ClassMetadata $metadata)
152 | If `false`, the php driver will be used, each document needs to have a mapping file
153 |
154 | Each **class_map** mapping may also specify the following options:
155 | * **map**:
156 | Array key represents the entity class name, value represents the mapping for the entity class
157 |
158 | * **met adata_cache** (Default: setting specified by mongodbodm.default_cache):
159 | String or array describing metadata cache implementation.
160 | * **types**
161 | An array of custom types in the format of 'typeName' => 'Namespace\To\Type\Class'
162 | * **mongodbodm.dms.options**:
163 | Array of Document Manager configuration sets indexed by each Document Manager's
164 | name. Each value should look like **mongodbodm.dm.options**.
165 |
166 | Example configuration:
167 |
168 | ```php
169 | [
173 | 'server' => 'mongodb://localhost:27017',
174 | 'options' => [
175 | 'username' => 'root',
176 | 'password' => 'root',
177 | 'db' => 'admin'
178 | ]
179 | ],
180 | 'mongo2' => [
181 | 'server' => 'mongodb://localhost:27018',
182 | 'options' => [
183 | 'username' => 'root',
184 | 'password' => 'root',
185 | 'db' => 'admin'
186 | ]
187 | ]
188 | ];
189 | ```
190 |
191 | Example usage:
192 |
193 | ```php
194 |
290 | * Beau Simensen ([Doctrine ORM Service Provider][2])
291 |
292 |
293 | [1]: https://github.com/dflydev
294 | [2]: https://github.com/dflydev/dflydev-doctrine-orm-service-provider
295 | [3]: https://github.com/dflydev/dflydev-psr0-resource-locator-service-provider
296 | [4]: https://packagist.org/packages/saxulum/saxulum-doctrine-mongodb-odm-provider
297 |
298 | [#silex-php]: irc://irc.freenode.net/#silex-php
299 |
--------------------------------------------------------------------------------
/tests/Provider/DoctrineMongoDbOdmProviderTest.php:
--------------------------------------------------------------------------------
1 | getMockBuilder('Doctrine\Common\EventManager')->disableOriginalConstructor()->getMock();
19 | $connection = $this->getMockBuilder('Doctrine\MongoDB\Connection')->disableOriginalConstructor()->getMock();
20 |
21 | $connection
22 | ->expects($this->any())
23 | ->method('getEventManager')
24 | ->will($this->returnValue($eventManager));
25 |
26 | $container['mongodbs'] = new Container([
27 | 'default' => $connection,
28 | ]);
29 |
30 | $container['mongodbs.event_manager'] = new Container([
31 | 'default' => $eventManager,
32 | ]);
33 |
34 | return [$container, $connection, $eventManager];
35 | }
36 |
37 | protected function createMockDefaultApp()
38 | {
39 | list($container, $connection, $eventManager) = $this->createMockDefaultAppAndDeps();
40 |
41 | return $container;
42 | }
43 |
44 | /**
45 | * Test registration (test expected class for default implementations).
46 | */
47 | public function testRegisterDefaultImplementations()
48 | {
49 | $container = $this->createMockDefaultApp();
50 |
51 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
52 | $doctrineOrmServiceProvider->register($container);
53 |
54 | $this->assertEquals($container['mongodbodm.dm'], $container['mongodbodm.dms']['default']);
55 | $this->assertInstanceOf('Doctrine\Common\Cache\ArrayCache', $container['mongodbodm.dm.config']->getMetadataCacheImpl());
56 | $this->assertInstanceOf('Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain', $container['mongodbodm.dm.config']->getMetadataDriverImpl());
57 | }
58 |
59 | /**
60 | * Test registration (test equality for defined implementations).
61 | */
62 | public function testRegisterDefinedImplementations()
63 | {
64 | $container = $this->createMockDefaultApp();
65 |
66 | $metadataCache = $this->getMockBuilder('Doctrine\Common\Cache\ArrayCache')
67 | ->disableOriginalConstructor()
68 | ->getMock();
69 |
70 | $mappingDriverChain = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain')
71 | ->disableOriginalConstructor()
72 | ->getMock();
73 |
74 | $container['mongodbodm.cache.instances.default.metadata'] = $metadataCache;
75 |
76 | $container['mongodbodm.mapping_driver_chain.instances.default'] = $mappingDriverChain;
77 |
78 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
79 | $doctrineOrmServiceProvider->register($container);
80 |
81 | $this->assertEquals($container['mongodbodm.dm'], $container['mongodbodm.dms']['default']);
82 | $this->assertEquals($metadataCache, $container['mongodbodm.dm.config']->getMetadataCacheImpl());
83 | $this->assertEquals($mappingDriverChain, $container['mongodbodm.dm.config']->getMetadataDriverImpl());
84 | }
85 |
86 | /**
87 | * Test proxy configuration (defaults).
88 | */
89 | public function testProxyConfigurationDefaults()
90 | {
91 | $container = $this->createMockDefaultApp();
92 |
93 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
94 | $doctrineOrmServiceProvider->register($container);
95 |
96 | $this->assertContains('/../../cache/doctrine/proxies', $container['mongodbodm.dm.config']->getProxyDir());
97 | $this->assertEquals('DoctrineProxy', $container['mongodbodm.dm.config']->getProxyNamespace());
98 | $this->assertTrue($container['mongodbodm.dm.config']->getAutoGenerateProxyClasses());
99 | }
100 |
101 | /**
102 | * Test proxy configuration (defined).
103 | */
104 | public function testProxyConfigurationDefined()
105 | {
106 | $container = $this->createMockDefaultApp();
107 |
108 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
109 | $doctrineOrmServiceProvider->register($container);
110 |
111 | $container['mongodbodm.proxies_dir'] = '/path/to/proxies';
112 | $container['mongodbodm.proxies_namespace'] = 'TestDoctrineMongoDbOdmProxiesNamespace';
113 | $container['mongodbodm.auto_generate_proxies'] = false;
114 |
115 | $this->assertEquals('/path/to/proxies', $container['mongodbodm.dm.config']->getProxyDir());
116 | $this->assertEquals('TestDoctrineMongoDbOdmProxiesNamespace', $container['mongodbodm.dm.config']->getProxyNamespace());
117 | $this->assertFalse($container['mongodbodm.dm.config']->getAutoGenerateProxyClasses());
118 | }
119 |
120 | /**
121 | * Test hydrator configuration (defaults).
122 | */
123 | public function testHydratorConfigurationDefaults()
124 | {
125 | $container = $this->createMockDefaultApp();
126 |
127 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
128 | $doctrineOrmServiceProvider->register($container);
129 |
130 | $this->assertContains('/../../cache/doctrine/hydrator', $container['mongodbodm.dm.config']->getHydratorDir());
131 | $this->assertEquals('DoctrineHydrator', $container['mongodbodm.dm.config']->getHydratorNamespace());
132 | $this->assertTrue($container['mongodbodm.dm.config']->getAutoGenerateHydratorClasses());
133 | }
134 |
135 | /**
136 | * Test hydrator configuration (defined).
137 | */
138 | public function testHydratorConfigurationDefined()
139 | {
140 | $container = $this->createMockDefaultApp();
141 |
142 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
143 | $doctrineOrmServiceProvider->register($container);
144 |
145 | $container['mongodbodm.hydrator_dir'] = '/path/to/hydrators';
146 | $container['mongodbodm.hydrator_namespace'] = 'TestDoctrineMongoDbOdmHydratorsNamespace';
147 | $container['mongodbodm.auto_generate_hydrators'] = false;
148 |
149 | $this->assertEquals('/path/to/hydrators', $container['mongodbodm.dm.config']->getHydratorDir());
150 | $this->assertEquals('TestDoctrineMongoDbOdmHydratorsNamespace', $container['mongodbodm.dm.config']->getHydratorNamespace());
151 | $this->assertFalse($container['mongodbodm.dm.config']->getAutoGenerateHydratorClasses());
152 | }
153 |
154 | /**
155 | * Test Driver Chain locator.
156 | */
157 | public function testMappingDriverChainLocator()
158 | {
159 | $container = $this->createMockDefaultApp();
160 |
161 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
162 | $doctrineOrmServiceProvider->register($container);
163 |
164 | $default = $container['mongodbodm.mapping_driver_chain.locator']();
165 | $this->assertEquals($default, $container['mongodbodm.mapping_driver_chain.locator']('default'));
166 | $this->assertEquals($default, $container['mongodbodm.dm.config']->getMetadataDriverImpl());
167 | }
168 |
169 | /**
170 | * Test adding a mapping driver (use default document manager).
171 | */
172 | public function testAddMappingDriverDefault()
173 | {
174 | $container = $this->createMockDefaultApp();
175 |
176 | $mappingDriver = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver')->disableOriginalConstructor()->getMock();
177 |
178 | $mappingDriverChain = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain')->disableOriginalConstructor()->getMock();
179 | $mappingDriverChain
180 | ->expects($this->once())
181 | ->method('addDriver')
182 | ->with($mappingDriver, 'Test\Namespace');
183 |
184 | $container['mongodbodm.mapping_driver_chain.instances.default'] = $mappingDriverChain;
185 |
186 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
187 | $doctrineOrmServiceProvider->register($container);
188 |
189 | $container['mongodbodm.add_mapping_driver']($mappingDriver, 'Test\Namespace');
190 | }
191 |
192 | /**
193 | * Test adding a mapping driver (specify default document manager by name).
194 | */
195 | public function testAddMappingDriverNamedEntityManager()
196 | {
197 | $container = $this->createMockDefaultApp();
198 |
199 | $mappingDriver = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\Driver\MappingDriver')->disableOriginalConstructor()->getMock();
200 |
201 | $mappingDriverChain = $this->getMockBuilder('Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain')->disableOriginalConstructor()->getMock();
202 | $mappingDriverChain
203 | ->expects($this->once())
204 | ->method('addDriver')
205 | ->with($mappingDriver, 'Test\Namespace');
206 |
207 | $container['mongodbodm.mapping_driver_chain.instances.default'] = $mappingDriverChain;
208 |
209 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
210 | $doctrineOrmServiceProvider->register($container);
211 |
212 | $container['mongodbodm.add_mapping_driver']($mappingDriver, 'Test\Namespace');
213 | }
214 |
215 | /**
216 | * Test mongodbodm.dm_name_from_param_key ().
217 | */
218 | public function testNameFromParamKey()
219 | {
220 | $container = $this->createMockDefaultApp();
221 |
222 | $container['my.baz'] = 'baz';
223 |
224 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
225 | $doctrineOrmServiceProvider->register($container);
226 |
227 | $container['mongodbodm.dms.default'] = 'foo';
228 |
229 | $this->assertEquals('foo', $container['mongodbodm.dms.default']);
230 | $this->assertEquals('foo', $container['mongodbodm.dm_name_from_param_key']('my.bar'));
231 | $this->assertEquals('baz', $container['mongodbodm.dm_name_from_param_key']('my.baz'));
232 | }
233 |
234 | /**
235 | * Test specifying an invalid mapping configuration (not an array of arrays).
236 | *
237 | * @expectedException \InvalidArgumentException
238 | * @expectedExceptionMessage The 'mongodbodm.dm.options' option 'mappings' should be an array of arrays.
239 | */
240 | public function testInvalidMappingAsOption()
241 | {
242 | $container = $this->createMockDefaultApp();
243 |
244 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
245 | $doctrineOrmServiceProvider->register($container);
246 |
247 | $container['mongodbodm.dm.options'] = [
248 | 'mappings' => [
249 | 'type' => 'annotation',
250 | 'namespace' => 'Foo\Entities',
251 | 'path' => __DIR__.'/src/Foo/Entities',
252 | ],
253 | ];
254 |
255 | $container['mongodbodm.dms.config'];
256 | }
257 |
258 | /**
259 | * Test if namespace alias can be set through the mapping options.
260 | */
261 | public function testMappingAlias()
262 | {
263 | $container = $this->createMockDefaultApp();
264 |
265 | $doctrineOrmServiceProvider = new DoctrineMongoDbOdmProvider();
266 | $doctrineOrmServiceProvider->register($container);
267 |
268 | $alias = 'Foo';
269 | $namespace = 'Foo\Entities';
270 |
271 | $container['mongodbodm.dm.options'] = [
272 | 'mappings' => [
273 | [
274 | 'type' => 'annotation',
275 | 'namespace' => $namespace,
276 | 'path' => __DIR__.'/src/Foo/Entities',
277 | 'alias' => $alias,
278 | ],
279 | ],
280 | ];
281 |
282 | $this->assertEquals($namespace, $container['mongodbodm.dm.config']->getDocumentNameSpace($alias));
283 | }
284 |
285 | public function testAnnotationMapping()
286 | {
287 | if (!extension_loaded('mongodb')) {
288 | $this->markTestSkipped('mongodb is not available');
289 | }
290 |
291 | $proxyPath = $this->getCacheDir().'/doctrine/proxies';
292 | $hydratorPath = $this->getCacheDir().'/doctrine/hydrator';
293 |
294 | @mkdir($proxyPath, 0777, true);
295 | @mkdir($hydratorPath, 0777, true);
296 |
297 | $app = new Container();
298 |
299 | $app->register(new DoctrineMongoDbProvider(), [
300 | 'mongodb.options' => [
301 | 'server' => 'mongodb://localhost:27017',
302 | ],
303 | ]);
304 |
305 | $app->register(new DoctrineMongoDbOdmProvider(), [
306 | 'mongodbodm.proxies_dir' => $proxyPath,
307 | 'mongodbodm.hydrator_dir' => $hydratorPath,
308 | 'mongodbodm.dm.options' => [
309 | 'database' => 'test',
310 | 'mappings' => [
311 | [
312 | 'type' => 'annotation',
313 | 'namespace' => 'Saxulum\\Tests\\DoctrineMongoDbOdm\\Document',
314 | 'path' => __DIR__.'../../Document',
315 | 'use_simple_annotation_reader' => false,
316 | ],
317 | ],
318 | ],
319 | ]);
320 |
321 | $title = 'title';
322 | $body = 'body';
323 |
324 | $page = new Page();
325 | $page->setTitle($title);
326 | $page->setBody($body);
327 |
328 | $app['mongodbodm.dm']->persist($page);
329 | $app['mongodbodm.dm']->flush();
330 |
331 | $repository = $app['mongodbodm.dm']
332 | ->getRepository('Saxulum\\Tests\\DoctrineMongoDbOdm\\Document\\Page')
333 | ;
334 | /** @var DocumentRepository $repository */
335 | $pageFromDb = $repository->findOneBy([], ['id' => 'DESC']);
336 | /* @var Page $pageFromDb */
337 |
338 | $this->assertEquals($title, $pageFromDb->getTitle());
339 | $this->assertEquals($body, $pageFromDb->getBody());
340 | }
341 |
342 | /**
343 | * @return string
344 | */
345 | protected function getCacheDir()
346 | {
347 | $cacheDir = __DIR__.'/../../cache';
348 |
349 | if (!is_dir($cacheDir)) {
350 | mkdir($cacheDir, 0777, true);
351 | }
352 |
353 | return $cacheDir;
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/src/Provider/DoctrineMongoDbOdmProvider.php:
--------------------------------------------------------------------------------
1 | getMongodbOdmDefaults($container) as $key => $value) {
39 | if (!isset($container[$key])) {
40 | $container[$key] = $value;
41 | }
42 | }
43 |
44 | $container['mongodbodm.dm.default_options'] = [
45 | 'connection' => 'default',
46 | 'database' => null,
47 | 'mappings' => [],
48 | 'types' => [],
49 | ];
50 |
51 | $container['mongodbodm.dms.options.initializer'] = $container->protect(function () use ($container) {
52 | static $initialized = false;
53 |
54 | if ($initialized) {
55 | return;
56 | }
57 |
58 | $initialized = true;
59 |
60 | if (!isset($container['mongodbodm.dms.options'])) {
61 | $container['mongodbodm.dms.options'] = ['default' => isset($container['mongodbodm.dm.options']) ? $container['mongodbodm.dm.options'] : []];
62 | }
63 |
64 | $tmp = $container['mongodbodm.dms.options'];
65 | foreach ($tmp as $name => &$options) {
66 | $options = array_replace($container['mongodbodm.dm.default_options'], $options);
67 |
68 | if (!isset($container['mongodbodm.dms.default'])) {
69 | $container['mongodbodm.dms.default'] = $name;
70 | }
71 | }
72 | $container['mongodbodm.dms.options'] = $tmp;
73 | });
74 |
75 | $container['mongodbodm.dm_name_from_param_key'] = $container->protect(function ($paramKey) use ($container) {
76 | $container['mongodbodm.dms.options.initializer']();
77 |
78 | if (isset($container[$paramKey])) {
79 | return $container[$paramKey];
80 | }
81 |
82 | return $container['mongodbodm.dms.default'];
83 | });
84 |
85 | $container['mongodbodm.dms'] = function () use ($container) {
86 | $container['mongodbodm.dms.options.initializer']();
87 |
88 | $dms = new Container();
89 | foreach ($container['mongodbodm.dms.options'] as $name => $options) {
90 | if ($container['mongodbodm.dms.default'] === $name) {
91 | // we use shortcuts here in case the default has been overridden
92 | $config = $container['mongodbodm.dm.config'];
93 | } else {
94 | $config = $container['mongodbodm.dms.config'][$name];
95 | }
96 |
97 | if (isset($options['database'])) {
98 | $config->setDefaultDB($options['database']);
99 | }
100 |
101 | $dms[$name] = function () use ($container, $options, $config) {
102 | return DocumentManager::create(
103 | $container['mongodbs'][$options['connection']],
104 | $config,
105 | $container['mongodbs.event_manager'][$options['connection']]
106 | );
107 | };
108 | }
109 |
110 | return $dms;
111 | };
112 |
113 | $container['mongodbodm.dms.config'] = function () use ($container) {
114 | $container['mongodbodm.dms.options.initializer']();
115 |
116 | $configs = new Container();
117 | foreach ($container['mongodbodm.dms.options'] as $name => $options) {
118 | $config = new Configuration();
119 |
120 | $container['mongodbodm.cache.configurer']($name, $config, $options);
121 |
122 | $config->setProxyDir($container['mongodbodm.proxies_dir']);
123 | $config->setProxyNamespace($container['mongodbodm.proxies_namespace']);
124 | $config->setAutoGenerateProxyClasses($container['mongodbodm.auto_generate_proxies']);
125 |
126 | $config->setHydratorDir($container['mongodbodm.hydrator_dir']);
127 | $config->setHydratorNamespace($container['mongodbodm.hydrator_namespace']);
128 | $config->setAutoGenerateHydratorClasses($container['mongodbodm.auto_generate_hydrators']);
129 |
130 | $config->setClassMetadataFactoryName($container['mongodbodm.class_metadata_factory_name']);
131 | $config->setDefaultRepositoryClassName($container['mongodbodm.default_repository_class']);
132 |
133 | $config->setRepositoryFactory($container['mongodbodm.repository_factory']);
134 |
135 | /** @var MappingDriverChain $chain */
136 | $chain = $container['mongodbodm.mapping_driver_chain.locator']($name);
137 | foreach ((array) $options['mappings'] as $entity) {
138 | if (!is_array($entity)) {
139 | throw new \InvalidArgumentException(
140 | "The 'mongodbodm.dm.options' option 'mappings' should be an array of arrays."
141 | );
142 | }
143 |
144 | if (isset($entity['alias'])) {
145 | $config->addDocumentNamespace($entity['alias'], $entity['namespace']);
146 | }
147 |
148 | switch ($entity['type']) {
149 | case 'annotation':
150 | $useSimpleAnnotationReader =
151 | isset($entity['use_simple_annotation_reader'])
152 | ? $entity['use_simple_annotation_reader']
153 | : true;
154 | $driver = $config->newDefaultAnnotationDriver((array) $entity['path'], $useSimpleAnnotationReader);
155 | $chain->addDriver($driver, $entity['namespace']);
156 | break;
157 | case 'yml':
158 | $driver = new YamlDriver($entity['path']);
159 | $chain->addDriver($driver, $entity['namespace']);
160 | break;
161 | case 'simple_yml':
162 | $driver = new SimplifiedYamlDriver([$entity['path'] => $entity['namespace']]);
163 | $chain->addDriver($driver, $entity['namespace']);
164 | break;
165 | case 'xml':
166 | $driver = new XmlDriver($entity['path']);
167 | $chain->addDriver($driver, $entity['namespace']);
168 | break;
169 | case 'simple_xml':
170 | $driver = new SimplifiedXmlDriver([$entity['path'] => $entity['namespace']]);
171 | $chain->addDriver($driver, $entity['namespace']);
172 | break;
173 | case 'php':
174 | if (!isset($entity['static']) || $entity['static']) {
175 | $driver = new StaticPHPDriver($entity['path']);
176 | } else {
177 | $driver = new PHPDriver($entity['path']);
178 | }
179 | $chain->addDriver($driver, $entity['namespace']);
180 | break;
181 | case 'class_map':
182 | $driver = new ClassMapDriver($entity['map']);
183 | $chain->addDriver($driver, $entity['namespace']);
184 | break;
185 | default:
186 | throw new \InvalidArgumentException(sprintf('"%s" is not a recognized driver', $entity['type']));
187 | break;
188 | }
189 | }
190 | $config->setMetadataDriverImpl($chain);
191 |
192 | foreach ((array) $options['types'] as $typeName => $typeClass) {
193 | if (Type::hasType($typeName)) {
194 | Type::overrideType($typeName, $typeClass);
195 | } else {
196 | Type::addType($typeName, $typeClass);
197 | }
198 | }
199 |
200 | $configs[$name] = $config;
201 | }
202 |
203 | return $configs;
204 | };
205 |
206 | $container['mongodbodm.cache.configurer'] = $container->protect(function ($name, Configuration $config, $options) use ($container) {
207 | $config->setMetadataCacheImpl($container['mongodbodm.cache.locator']($name, 'metadata', $options));
208 | });
209 |
210 | $container['mongodbodm.cache.locator'] = $container->protect(function ($name, $cacheName, $options) use ($container) {
211 | $cacheNameKey = $cacheName.'_cache';
212 |
213 | if (!isset($options[$cacheNameKey])) {
214 | $options[$cacheNameKey] = $container['mongodbodm.default_cache'];
215 | }
216 |
217 | if (isset($options[$cacheNameKey]) && !is_array($options[$cacheNameKey])) {
218 | $options[$cacheNameKey] = [
219 | 'driver' => $options[$cacheNameKey],
220 | ];
221 | }
222 |
223 | if (!isset($options[$cacheNameKey]['driver'])) {
224 | throw new \RuntimeException("No driver specified for '$cacheName'");
225 | }
226 |
227 | $driver = $options[$cacheNameKey]['driver'];
228 |
229 | $cacheInstanceKey = 'mongodbodm.cache.instances.'.$name.'.'.$cacheName;
230 | if (isset($container[$cacheInstanceKey])) {
231 | return $container[$cacheInstanceKey];
232 | }
233 |
234 | $cache = $container['mongodbodm.cache.factory']($driver, $options[$cacheNameKey]);
235 |
236 | if (isset($options['cache_namespace']) && $cache instanceof CacheProvider) {
237 | $cache->setNamespace($options['cache_namespace']);
238 | }
239 |
240 | return $container[$cacheInstanceKey] = $cache;
241 | });
242 |
243 | $container['mongodbodm.cache.factory.backing_memcache'] = $container->protect(function () {
244 | return new \Memcache();
245 | });
246 |
247 | $container['mongodbodm.cache.factory.memcache'] = $container->protect(function ($cacheOptions) use ($container) {
248 | if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
249 | throw new \RuntimeException('Host and port options need to be specified for memcache cache');
250 | }
251 |
252 | /** @var \Memcache $memcache */
253 | $memcache = $container['mongodbodm.cache.factory.backing_memcache']();
254 | $memcache->connect($cacheOptions['host'], $cacheOptions['port']);
255 |
256 | $cache = new MemcacheCache();
257 | $cache->setMemcache($memcache);
258 |
259 | return $cache;
260 | });
261 |
262 | $container['mongodbodm.cache.factory.backing_memcached'] = $container->protect(function () {
263 | return new \Memcached();
264 | });
265 |
266 | $container['mongodbodm.cache.factory.memcached'] = $container->protect(function ($cacheOptions) use ($container) {
267 | if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
268 | throw new \RuntimeException('Host and port options need to be specified for memcached cache');
269 | }
270 |
271 | /** @var \Memcached $memcached */
272 | $memcached = $container['mongodbodm.cache.factory.backing_memcached']();
273 | $memcached->addServer($cacheOptions['host'], $cacheOptions['port']);
274 |
275 | $cache = new MemcachedCache();
276 | $cache->setMemcached($memcached);
277 |
278 | return $cache;
279 | });
280 |
281 | $container['mongodbodm.cache.factory.backing_redis'] = $container->protect(function () {
282 | return new \Redis();
283 | });
284 |
285 | $container['mongodbodm.cache.factory.redis'] = $container->protect(function ($cacheOptions) use ($container) {
286 | if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
287 | throw new \RuntimeException('Host and port options need to be specified for redis cache');
288 | }
289 |
290 | /** @var \Redis $redis */
291 | $redis = $container['mongodbodm.cache.factory.backing_redis']();
292 | $redis->connect($cacheOptions['host'], $cacheOptions['port']);
293 |
294 | if (isset($cacheOptions['password'])) {
295 | $redis->auth($cacheOptions['password']);
296 | }
297 |
298 | $cache = new RedisCache();
299 | $cache->setRedis($redis);
300 |
301 | return $cache;
302 | });
303 |
304 | $container['mongodbodm.cache.factory.array'] = $container->protect(function () {
305 | return new ArrayCache();
306 | });
307 |
308 | $container['mongodbodm.cache.factory.apc'] = $container->protect(function () {
309 | return new ApcCache();
310 | });
311 |
312 | $container['mongodbodm.cache.factory.apcu'] = $container->protect(function () {
313 | return new ApcuCache();
314 | });
315 |
316 | $container['mongodbodm.cache.factory.xcache'] = $container->protect(function () {
317 | return new XcacheCache();
318 | });
319 |
320 | $container['mongodbodm.cache.factory.filesystem'] = $container->protect(function ($cacheOptions) {
321 | if (empty($cacheOptions['path'])) {
322 | throw new \RuntimeException('FilesystemCache path not defined');
323 | }
324 |
325 | $cacheOptions += [
326 | 'extension' => FilesystemCache::EXTENSION,
327 | 'umask' => 0002,
328 | ];
329 |
330 | return new FilesystemCache($cacheOptions['path'], $cacheOptions['extension'], $cacheOptions['umask']);
331 | });
332 |
333 | $container['mongodbodm.cache.factory.couchbase'] = $container->protect(function ($cacheOptions) {
334 | if (empty($cacheOptions['host'])) {
335 | $cacheOptions['host'] = '127.0.0.1';
336 | }
337 |
338 | if (empty($cacheOptions['bucket'])) {
339 | $cacheOptions['bucket'] = 'default';
340 | }
341 |
342 | $couchbase = new \Couchbase(
343 | $cacheOptions['host'],
344 | $cacheOptions['user'],
345 | $cacheOptions['password'],
346 | $cacheOptions['bucket']
347 | );
348 |
349 | $cache = new CouchbaseCache();
350 | $cache->setCouchbase($couchbase);
351 |
352 | return $cache;
353 | });
354 |
355 | $container['mongodbodm.cache.factory'] = $container->protect(function ($driver, $cacheOptions) use ($container) {
356 | switch ($driver) {
357 | case 'array':
358 | return $container['mongodbodm.cache.factory.array']();
359 | case 'apc':
360 | return $container['mongodbodm.cache.factory.apc']();
361 | case 'apcu':
362 | return $container['mongodbodm.cache.factory.apcu']();
363 | case 'xcache':
364 | return $container['mongodbodm.cache.factory.xcache']();
365 | case 'memcache':
366 | return $container['mongodbodm.cache.factory.memcache']($cacheOptions);
367 | case 'memcached':
368 | return $container['mongodbodm.cache.factory.memcached']($cacheOptions);
369 | case 'filesystem':
370 | return $container['mongodbodm.cache.factory.filesystem']($cacheOptions);
371 | case 'redis':
372 | return $container['mongodbodm.cache.factory.redis']($cacheOptions);
373 | case 'couchbase':
374 | return $container['mongodbodm.cache.factory.couchbase']($cacheOptions);
375 | default:
376 | throw new \RuntimeException("Unsupported cache type '$driver' specified");
377 | }
378 | });
379 |
380 | $container['mongodbodm.mapping_driver_chain.locator'] = $container->protect(function ($name = null) use ($container) {
381 | $container['mongodbodm.dms.options.initializer']();
382 |
383 | if (null === $name) {
384 | $name = $container['mongodbodm.dms.default'];
385 | }
386 |
387 | $cacheInstanceKey = 'mongodbodm.mapping_driver_chain.instances.'.$name;
388 | if (isset($container[$cacheInstanceKey])) {
389 | return $container[$cacheInstanceKey];
390 | }
391 |
392 | return $container[$cacheInstanceKey] = $container['mongodbodm.mapping_driver_chain.factory']($name);
393 | });
394 |
395 | $container['mongodbodm.mapping_driver_chain.factory'] = $container->protect(function ($name) use ($container) {
396 | return new MappingDriverChain();
397 | });
398 |
399 | $container['mongodbodm.add_mapping_driver'] = $container->protect(function (MappingDriver $mappingDriver, $namespace, $name = null) use ($container) {
400 | $container['mongodbodm.dms.options.initializer']();
401 |
402 | if (null === $name) {
403 | $name = $container['mongodbodm.dms.default'];
404 | }
405 |
406 | /** @var MappingDriverChain $driverChain */
407 | $driverChain = $container['mongodbodm.mapping_driver_chain.locator']($name);
408 | $driverChain->addDriver($mappingDriver, $namespace);
409 | });
410 |
411 | $container['mongodbodm.repository_factory'] = function ($container) {
412 | return new DefaultRepositoryFactory();
413 | };
414 |
415 | $container['mongodbodm.dm'] = function ($container) {
416 | $dms = $container['mongodbodm.dms'];
417 |
418 | return $dms[$container['mongodbodm.dms.default']];
419 | };
420 |
421 | $container['mongodbodm.dm.config'] = function ($container) {
422 | $configs = $container['mongodbodm.dms.config'];
423 |
424 | return $configs[$container['mongodbodm.dms.default']];
425 | };
426 | }
427 |
428 | /**
429 | * @param Container $container
430 | *
431 | * @return array
432 | */
433 | protected function getMongodbOdmDefaults(Container $container)
434 | {
435 | return [
436 | 'mongodbodm.proxies_dir' => __DIR__.'/../../cache/doctrine/proxies',
437 | 'mongodbodm.proxies_namespace' => 'DoctrineProxy',
438 | 'mongodbodm.auto_generate_proxies' => true,
439 | 'mongodbodm.default_cache' => [
440 | 'driver' => 'array',
441 | ],
442 | 'mongodbodm.hydrator_dir' => __DIR__.'/../../cache/doctrine/hydrator',
443 | 'mongodbodm.hydrator_namespace' => 'DoctrineHydrator',
444 | 'mongodbodm.auto_generate_hydrators' => true,
445 | 'mongodbodm.class_metadata_factory_name' => 'Doctrine\ODM\MongoDB\Mapping\ClassMetadataFactory',
446 | 'mongodbodm.default_repository_class' => 'Doctrine\ODM\MongoDB\DocumentRepository',
447 | ];
448 | }
449 | }
450 |
--------------------------------------------------------------------------------