Silex + Couchdb + DoctrineCouchDbODM

С Рождеством всех.

Я пытаюсь использовать доктрину couchdb-ODM с проектом php Silex. Я уже получил это, работая с доктринами, но с диваном, он продолжает ломаться.

Я искал в Интернете несколько дней, но ничего. Я буду конкретен, я получаю эту забавную ошибку


Class Package\documents\User is not a valid document or mapped super class.

При отладке я заметил этот вызов в строке 55 Doctrine / ODM / CouchDB / Mapping / Driver / AnnotationDriver.php

$classAnnotations = $this->reader->getClassAnnotations($reflClass);

Возвращает пустой массив. Думаю, что-то не так с моей конфигурацией, но, похоже, не могу это указать.

Любая помощь будет оценена.

Обновить
Настроить CouchDB ODM. Я создал 2 поставщиков услуг. 1 для CouchDB и другой для CouchDB ODM, смоделированный по умолчанию DoctrineServiceProvider в Silex

Поставщик услуг CouchDB

<?php

namespace Package\services\Doctrine\CouchDB;

use Pimple\Container;
use Pimple\ServiceProviderInterface;

use Doctrine\CouchDB\CouchDBClient;
use Doctrine\DBAL\Configuration;
use Doctrine\Common\EventManager;
use Doctrine\CouchDB\HTTP\SocketClient;

use Symfony\Bridge\Doctrine\Logger\DbalLogger;

class DoctrineCouchDbServiceProvider implements ServiceProviderInterface {
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param Application $container An Application instance
*/
public function register(Container $container) {
$container['couchdb.default_options'] = [
'type' => 'socket',
'host' => 'localhost',
'port' => 5984,
'user' => null,
'password' => null,
'ip' => null,
'logging' => true
];

$container['couchdbs.options.initializer'] = $container->protect(function () use ($container) {
static $initialized = false;

if ($initialized) {
return;
}

$initialized = true;

if (!isset($container['couchdbs.options'])) {
$container['couchdbs.options'] = [
'default' => isset($container['couchdb.options']) ? $container['couchdb.options'] : []
];
}

$tmp = $container['couchdbs.options'];
foreach ($tmp as $name => &$options) {
$options = array_replace_recursive($container['couchdb.default_options'], $options);

if (!isset($container['couchdbs.default'])) {
$container['couchdbs.default'] = $name;
}
}
$container['couchdbs.options'] = $tmp;
});

$container['couchdbs'] = function($container) {
$container['couchdbs.options.initializer']();

$couchdbs = new Container();
foreach ($container['couchdbs.options'] as $name => $options) {
if ($container['couchdbs.default'] === $name) {
// we use shortcuts here in case the default has been overridden
$config = $container['couchdb.config'];
$manager = $container['couchdb.event_manager'];
} else {
$config = $container['couchdbs.config'][$name];
$manager = $container['couchdbs.event_manager'][$name];
}

$couchdbs[$name] = function () use ($options, $config, $manager) {
return CouchDBClient::create($options);
};
}

return $couchdbs;
};

$container['couchdbs.config'] = function ($container) {
$container['couchdbs.options.initializer']();

$configs = new Container();
$addLogger = isset($container['logger']) && null !== $container['logger'] && class_exists('Symfony\Bridge\Doctrine\Logger\DbalLogger');
foreach ($container['couchdbs.options'] as $name => $options) {
$configs[$name] = new Configuration();
if ($addLogger) {
$configs[$name]->setSQLLogger(new DbalLogger($container['logger'], isset($container['stopwatch']) ? $container['stopwatch'] : null));
}
}
return $configs;
};

$container['couchdbs.event_manager'] = function ($container) {
$container['couchdbs.options.initializer']();

$managers = new Container();
foreach ($container['couchdbs.options'] as $name => $options) {
$managers[$name] = new EventManager();
}

return $managers;
};

// shortcuts for the "first" DB
$container['couchdb'] = function ($container) {
$couchdbs = $container['couchdbs'];

return $couchdbs[$container['couchdbs.default']];
};

$container['couchdb.config'] = function ($container) {
$couchdbs = $container['couchdbs.config'];

return $couchdbs[$container['couchdbs.default']];
};

$container['couchdb.event_manager'] = function ($container) {
$couchdbs = $container['couchdbs.event_manager'];

return $couchdbs[$container['couchdbs.default']];
};
}
}

Поставщик услуг CouchDB ODM

<?php

namespace Package\services\Doctrine\CouchDB;

use Pimple\Container;
use Pimple\ServiceProviderInterface;

use Doctrine\Common\Cache\ApcCache;
use Doctrine\Common\Cache\ArrayCache;
use Doctrine\Common\Cache\CacheProvider;
use Doctrine\Common\Cache\CouchbaseCache;
use Doctrine\Common\Cache\FilesystemCache;
use Doctrine\Common\Cache\MemcacheCache;
use Doctrine\Common\Cache\MemcachedCache;
use Doctrine\Common\Cache\RedisCache;
use Doctrine\Common\Cache\XcacheCache;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriver;
use Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain;

use Doctrine\CouchDB\CouchDBClient;
use Doctrine\ODM\CouchDB\Configuration;
use Doctrine\ODM\CouchDB\DocumentManager;
use Doctrine\ODM\CouchDB\Mapping\Driver\DriverChain;
use Doctrine\ODM\CouchDB\Mapping\Driver\AnnotationDriver;
use Doctrine\ODM\CouchDB\Mapping\Driver\PHPDriver;
use Doctrine\ODM\CouchDB\Mapping\Driver\XmlDriver;
use Doctrine\ODM\CouchDB\Mapping\Driver\YamlDriver;
use Doctrine\ODM\CouchDB\Types\Type;

class DoctrineCouchDbOdmServiceProvider implements ServiceProviderInterface {
/**
* Registers services on the given app.
*
* This method should only be used to configure services and parameters.
* It should not get services.
*
* @param Application $container An Application instance
*/
public function register(Container $container) {
foreach ($this->getCouchDbOdmDefaults($container) as $key => $value) {
if (!isset($container[$key])) {
$container[$key] = $value;
}
}

$container['couchdb.dm.default_options'] = [
'connection' => 'default',
'mappings' => [],
'types' => [],
];

$container['couchdb.dms.options.initializer'] = $container->protect(function () use ($container) {
static $initialized = false;

if ($initialized) {
return;
}

$initialized = true;


if (!isset($container['couchdb.dms.options'])) {
$container['couchdb.dms.options'] = [
'default' => isset($container['couchdb.dm.options']) ? $container['couchdb.dm.options'] : []
];
}

$tmp = $container['couchdb.dms.options'];
foreach ($tmp as $name => &$options) {
$options = array_replace($container['couchdb.dm.default_options'], $options);

if (!isset($container['couchdb.dms.default'])) {
$container['couchdb.dms.default'] = $name;
}
}
$container['couchdb.dms.options'] = $tmp;
});

$container['couchdb.dm_name_from_param_key'] = $container->protect(function ($paramKey) use ($container) {
$container['couchdb.dms.options.initializer']();

if (isset($container[$paramKey])) {
return $container[$paramKey];
}

return $container['couchdb.dms.default'];
});

$container['couchdb.dms'] = function($container) {
$container['couchdb.dms.options.initializer']();

$dms = new Container();
foreach ($container['couchdb.dms.options'] as $name => $options) {
if ($container['couchdb.dms.default'] === $name) {
// we use shortcuts here in case the default has been overridden
$config = $container['couchdb.dm.config'];
} else {
$config = $container['couchdb.dms.config'][$name];
}

if (isset($options['dbname'])) {
$config->setDefaultDB($options['dbname']);
}

// print_r($options);
$dms[$name] = function ($dms) use ($container, $options, $config) {
$httpClient = new \Doctrine\CouchDB\HTTP\SocketClient();
$dm = DocumentManager::create(
CouchDBClient::create($container['couchdb.options']),
$config,
$container['couchdbs.event_manager'][$options['connection']]
);

return $dm;
};
}

return $dms;
};

$container['couchdb.dms.config'] = function($container) {
$container['couchdb.dms.options.initializer']();

$configs = new Container();
foreach ($container['couchdb.dms.options'] as $name => $options) {
$config = new Configuration;

$container['couchdb.cache.configurer']($name, $config, $options);

$config->setProxyDir($container['couchdb.proxies_dir']);
$config->setProxyNamespace($container['couchdb.proxies_namespace']);
$config->setAutoGenerateProxyClasses($container['couchdb.auto_generate_proxies']);
$config->setValidateDoctrineMetadata($container['couchdb.validate_doctrine_metadata']);
$config->setAllOrNothingFlush($container['couchdb.all_or_nothing_flush']);
$config->setLuceneHandlerName('_fti');

$chain = $container['couchdb.mapping_driver_chain.locator']($name);
foreach ((array) $options['mappings'] as $document) {
if (!is_array($document)) {
throw new \InvalidArgumentException(
"The 'couchdb.dm.options' option 'mappings' should be an array of arrays.");
}

if (!empty($document['resources_namespace'])) {
$document['path'] = $container['psr0_resource_locator']->findFirstDirectory($document['resources_namespace']);
}

if (isset($document['alias'])) {
$config->addDocumentNamespace($document['alias'], $document['namespace']);
}

switch ($document['type']) {
case 'annotation':
$useSimpleAnnotationReader =
isset($document['use_simple_annotation_reader'])
? $document['use_simple_annotation_reader']
: true;
$driver = $config->newDefaultAnnotationDriver((array) $document['path'], $useSimpleAnnotationReader);
$chain->addDriver($driver, $document['namespace']);
break;
case 'annotation2':
$driver = new AnnotationDriver($document['path']);
$chain->addDriver($driver, $document['namespace']);
break;
case 'yml':
$driver = new YamlDriver($document['path']);
$chain->addDriver($driver, $document['namespace']);
break;
case 'xml':
$driver = new XmlDriver($document['path']);
$chain->addDriver($driver, $document['namespace']);
break;
case 'php':
$driver = new PHPDriver($document['path']);
$chain->addDriver($driver, $document['namespace']);
break;
default:
throw new \InvalidArgumentException(sprintf('"%s" is not a recognized driver', $document['type']));
break;
}
}
$config->setMetadataDriverImpl($chain);

foreach ((array) $options['types'] as $typeName => $typeClass) {
if (Type::hasType($typeName)) {
Type::overrideType($typeName, $typeClass);
} else {
Type::addType($typeName, $typeClass);
}
}
$configs[$name] = $config;
}
return $configs;
};

$container['couchdb.cache.configurer'] = $container->protect(function ($name, Configuration $config, $options) use ($container) {
$config->setMetadataCacheImpl($container['couchdb.cache.locator']($name, 'metadata', $options));
});

$container['couchdb.cache.locator'] = $container->protect(function ($name, $cacheName, $options) use ($container) {
$cacheNameKey = $cacheName . '_cache';

if (!isset($options[$cacheNameKey])) {
$options[$cacheNameKey] = $container['couchdb.default_cache'];
}

if (isset($options[$cacheNameKey]) && !is_array($options[$cacheNameKey])) {
$options[$cacheNameKey] = array(
'driver' => $options[$cacheNameKey],
);
}

if (!isset($options[$cacheNameKey]['driver'])) {
throw new \RuntimeException("No driver specified for '$cacheName'");
}

$driver = $options[$cacheNameKey]['driver'];

$cacheInstanceKey = 'couchdb.cache.instances.'.$name.'.'.$cacheName;
if (isset($container[$cacheInstanceKey])) {
return $container[$cacheInstanceKey];
}

$cache = $container['couchdb.cache.factory']($driver, $options[$cacheNameKey]);

if (isset($options['cache_namespace']) && $cache instanceof CacheProvider) {
$cache->setNamespace($options['cache_namespace']);
}

return $container[$cacheInstanceKey] = $cache;
});

$container['couchdb.cache.factory.backing_memcache'] = $container->protect(function () {
return new \Memcache;
});

$container['couchdb.cache.factory.memcache'] = $container->protect(function ($cacheOptions) use ($container) {
if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
throw new \RuntimeException('Host and port options need to be specified for memcache cache');
}

$memcache = $container['couchdb.cache.factory.backing_memcache']();
$memcache->connect($cacheOptions['host'], $cacheOptions['port']);

$cache = new MemcacheCache;
$cache->setMemcache($memcache);

return $cache;
});

$container['couchdb.cache.factory.backing_memcached'] = $container->protect(function () {
return new \Memcached;
});

$container['couchdb.cache.factory.memcached'] = $container->protect(function ($cacheOptions) use ($container) {
if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
throw new \RuntimeException('Host and port options need to be specified for memcached cache');
}

$memcached = $container['couchdb.cache.factory.backing_memcached']();
$memcached->addServer($cacheOptions['host'], $cacheOptions['port']);

$cache = new MemcachedCache;
$cache->setMemcached($memcached);

return $cache;
});

$container['couchdb.cache.factory.backing_memcached'] = $container->protect(function () {
return new \Memcached;
});

$container['couchdb.cache.factory.memcached'] = $container->protect(function ($cacheOptions) use ($container) {
if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
throw new \RuntimeException('Host and port options need to be specified for memcached cache');
}

/** @var \Memcached $memcached */
$memcached = $container['couchdb.cache.factory.backing_memcached']();
$memcached->addServer($cacheOptions['host'], $cacheOptions['port']);

$cache = new MemcachedCache;
$cache->setMemcached($memcached);

return $cache;
});

$container['couchdb.cache.factory.backing_redis'] = $container->protect(function () {
return new \Redis;
});

$container['couchdb.cache.factory.redis'] = $container->protect(function ($cacheOptions) use ($container) {
if (empty($cacheOptions['host']) || empty($cacheOptions['port'])) {
throw new \RuntimeException('Host and port options need to be specified for redis cache');
}

/** @var \Redis $redis */
$redis = $container['couchdb.cache.factory.backing_redis']();
$redis->connect($cacheOptions['host'], $cacheOptions['port']);

if (isset($cacheOptions['password'])) {
$redis->auth($cacheOptions['password']);
}

$cache = new RedisCache;
$cache->setRedis($redis);

return $cache;
});

$container['couchdb.cache.factory.array'] = $container->protect(function () {
return new ArrayCache;
});

$container['couchdb.cache.factory.apc'] = $container->protect(function () {
return new ApcCache;
});

$container['couchdb.cache.factory.xcache'] = $container->protect(function () {
return new XcacheCache;
});

$container['couchdb.cache.factory.filesystem'] = $container->protect(function ($cacheOptions) {
if (empty($cacheOptions['path'])) {
throw new \RuntimeException('FilesystemCache path not defined');
}

$cacheOptions += array(
'extension' => FilesystemCache::EXTENSION,
'umask' => 0002,
);

return new FilesystemCache($cacheOptions['path'], $cacheOptions['extension'], $cacheOptions['umask']);
});

$container['couchdb.cache.factory.couchbase'] = $container->protect(function ($cacheOptions) {
$host='';
$bucketName='';
$user='';
$password='';
if (empty($cacheOptions['host'])) {
$host='127.0.0.1';
}
if (empty($cacheOptions['bucket'])) {
$bucketName='default';
}
if (!empty($cacheOptions['user'])) {
$user=$cacheOptions['user'];
}
if (!empty($cacheOptions['password'])) {
$password=$cacheOptions['password'];
}

$couchbase = new \Couchbase($host,$user,$password,$bucketName);
$cache = new CouchbaseCache();
$cache->setCouchbase($couchbase);
return $cache;
});

$container['couchdb.cache.factory'] = $container->protect(function ($driver, $cacheOptions) use ($container) {
switch ($driver) {
case 'array':
return $container['couchdb.cache.factory.array']();
case 'apc':
return $container['couchdb.cache.factory.apc']();
case 'xcache':
return $container['couchdb.cache.factory.xcache']();
case 'memcache':
return $container['couchdb.cache.factory.memcache']($cacheOptions);
case 'memcached':
return $container['couchdb.cache.factory.memcached']($cacheOptions);
case 'filesystem':
return $container['couchdb.cache.factory.filesystem']($cacheOptions);
case 'redis':
return $container['couchdb.cache.factory.redis']($cacheOptions);
case 'couchbase':
return $container['couchdb.cache.factory.couchbase']($cacheOptions);
default:
throw new \RuntimeException("Unsupported cache type '$driver' specified");
}
});

$container['couchdb.mapping_driver_chain.locator'] = $container->protect(function ($name = null) use ($container) {
$container['couchdb.dms.options.initializer']();

if (null === $name) {
$name = $container['couchdb.dms.default'];
}

$cacheInstanceKey = 'couchdb.mapping_driver_chain.instances.'.$name;
if (isset($container[$cacheInstanceKey])) {
return $container[$cacheInstanceKey];
}

return $container[$cacheInstanceKey] = $container['couchdb.mapping_driver_chain.factory']($name);
});

$container['couchdb.mapping_driver_chain.factory'] = $container->protect(function ($name) use ($container) {
return new DriverChain;
});

$container['couchdb.add_mapping_driver'] = $container->protect(function (MappingDriver $mappingDriver, $namespace, $name = null) use ($container) {
$container['couchdb.dms.options.initializer']();

if (null === $name) {
$name = $container['couchdb.dms.default'];
}

$driverChain = $container['couchdb.mapping_driver_chain.locator']($name);
$driverChain->addDriver($mappingDriver, $namespace);
});

$container['couchdb.generate_psr0_mapping'] = $container->protect(function ($resourceMapping) use ($container) {
$mapping = [];
foreach ($resourceMapping as $resourceNamespace => $documentNamespace) {
$directory = $container['psr0_resource_locator']->findFirstDirectory($resourceNamespace);
if (!$directory) {
throw new \InvalidArgumentException("Resources for mapping '$documentNamespace' could not be located; Looked for mapping resources at '$resourceNamespace'");
}
$mapping[$directory] = $documentNamespace;
}

return $mapping;
});

$container['couchdb.dm'] = function($container) {
$dms = $container['couchdb.dms'];

return $dms[$container['couchdb.dms.default']];
};

$container['couchdb.dm.config'] = function($container) {
$configs = $container['couchdb.dms.config'];

return $configs[$container['couchdb.dms.default']];
};
}

/**
* @param  \Pimple $container
* @return array
*/
protected function getCouchDbOdmDefaults(Container $container) {
return array(
'couchdb.proxies_dir' => __DIR__.'/../../../../../var/cache/doctrine/proxies',
'couchdb.proxies_namespace' => 'CouchDBDoctrineProxy',
'couchdb.proxy_namespace' => 'MyCouchDBProxyNS',
'couchdb.auto_generate_proxies' => true,
'couchdb.auto_generate_proxy_classes' => true,
'couchdb.default_cache' => [
'driver' => 'array',
],
'couchdb.write_doctrine_metadata' => true,
'couchdb.validate_doctrine_metadata' => true,
'couchdb.uuid_generationbuffersize' => 20,
'couchdb.all_or_nothing_flush' => true,
'couchdb.lucene_handler_name' => '_fti',
'couchdb.metadata_resolver' => null,
'couchdb.class_metadata_factory_name' => '\Doctrine\ODM\CouchDB\Mapping\ClassMetadataFactory',
'couchdb.default_repository_class' => '\Doctrine\ODM\CouchDB\DocumentRepository',
);
}
}

Я тогда зарегистрировался как в app.php

$app->register(new DoctrineCouchDbServiceProvider());
$app->register(new DoctrineCouchDbOdmServiceProvider());

и добавил параметры дивана дБ и конфигурации в config/prod.php

$app['couchdb.options'] = [
'dbname' => 'app_db',
'type' => 'socket',
'host' => 'localhost',
'port' => 5984,
'user' => null,
'password' => null,
'ip' => null,
'logging' => true
];

$app['couchdb.dm.options'] = [
'mappings' => [
[
'type' => 'annotation',
'namespace' => 'Package\documents',
'path' => __DIR__.'/../src/package/documents'
],
]
];

Мои документы

<?php
namespace Package\documents;

use Doctrine\ODM\CouchDB\Mapping\Annotations as CouchDB;
use Gedmo\Mapping\Annotation as Gedmo;

use Doctrine\Common\Collections\ArrayCollection;

// Have tried @CouchDB\Document as well

/**
* @Document(repositoryClass="repositories\ZoneRepository")
*/
class Zone {
/**
* @Id(type="string")
*/
protected $id;

/**
* @Field(type="string", indexed=true)
*/
protected $slug;

/**
* @Field(type="string", jsonName="name", indexed=true)
*/
protected $name;

/** @Field(type="boolean", jsonName="enabled") */
protected $enabled;
}

Долго читаю, но надеюсь, это поможет вам разобраться в проблеме.
Спасибо за помощь

1

Решение

Задача ещё не решена.

Другие решения

Других решений пока нет …