* @license GPLv2 */ class PersistenceManager extends ConfigurableService { public const SERVICE_ID = 'generis/persistences'; public const OPTION_PERSISTENCES = 'persistences'; /** * Mapping of drivers to implementations. * All SQL drivers except 'dbal' are deprecated * @var array */ private const DRIVER_MAP = [ 'dbal' => 'common_persistence_sql_dbal_Driver', 'dbal_pdo_mysql' => 'common_persistence_sql_dbal_Driver', 'dbal_pdo_sqlite' => 'common_persistence_sql_dbal_Driver', 'dbal_pdo_pgsql' => 'common_persistence_sql_dbal_Driver', 'dbal_pdo_ibm' => 'common_persistence_sql_dbal_Driver', 'phpredis' => 'common_persistence_PhpRedisDriver', 'phpfile' => 'common_persistence_PhpFileDriver', 'SqlKvWrapper' => 'common_persistence_SqlKvDriver', 'no_storage' => 'common_persistence_InMemoryKvDriver', 'no_storage_adv' => 'common_persistence_InMemoryAdvKvDriver' ]; /** * * @var array */ private $persistences = []; /** * Returns TRUE if the requested persistence exist, otherwise FALSE. * * @param string $persistenceId * @return bool */ public function hasPersistence($persistenceId) { $persistenceList = $this->getOption(static::OPTION_PERSISTENCES); return isset($persistenceList[$persistenceId]); } /** * Registers a new persistence. * * @param string $persistenceId * @param array $persistenceConf */ public function registerPersistence($persistenceId, array $persistenceConf) { // wrap pdo drivers in dbal if (strpos($persistenceConf['driver'], 'pdo_') === 0) { $persistenceConf = [ 'driver' => 'dbal', 'connection' => $persistenceConf ]; } if ( isset($persistenceConf['connection']['driver']) && $persistenceConf['connection']['driver'] === 'pdo_mysql' ) { $persistenceConf['connection']['charset'] = 'utf8'; } $configs = $this->getOption(self::OPTION_PERSISTENCES); $configs[$persistenceId] = $persistenceConf; $this->setOption(self::OPTION_PERSISTENCES, $configs); } /** * * @return \common_persistence_Persistence */ public function getPersistenceById($persistenceId) { if (!isset($this->persistences[$persistenceId])) { $this->persistences[$persistenceId] = $this->createPersistence($persistenceId); } return $this->persistences[$persistenceId]; } /** * * @param string $persistenceId * @return \common_persistence_Persistence * @throws \common_Exception */ private function createPersistence($persistenceId) { $configs = $this->getOption(self::OPTION_PERSISTENCES); if (!isset($configs[$persistenceId])) { throw new \common_Exception('Persistence Configuration for persistence ' . $persistenceId . ' not found'); } $config = $configs[$persistenceId]; $driverString = $config['driver']; $driverClassName = isset(self::DRIVER_MAP[$driverString]) ? self::DRIVER_MAP[$driverString] : $driverString; if (!class_exists($driverClassName)) { throw new \common_exception_Error( 'Driver ' . $driverString . ' not found, check your database configuration' ); } $driver = $this->propagate(new $driverClassName()); $driverOptionsFeeder = $this->getDriverConfigFeeder(); if ($driverOptionsFeeder !== null) { $config = $driverOptionsFeeder->feed($config); } return $driver->connect($persistenceId, $config); } /** * Return a collection of all SQL schemas */ public function getSqlSchemas() { $schemas = new SchemaCollection(); foreach (array_keys($this->getOption(self::OPTION_PERSISTENCES)) as $id) { $persistence = $this->getPersistenceById($id); if ($persistence instanceof common_persistence_SqlPersistence) { $schemas->addSchema($id, $persistence->getSchemaManager()->createSchema()); } } return $schemas; } /** * Adapt the databases to the SQL schemas */ public function applySchemas(SchemaCollection $schemaCollection) { $this->logInfo('Applying schame changes'); foreach ($schemaCollection as $id => $schema) { $persistence = $this->getPersistenceById($id); $fromSchema = $schemaCollection->getOriginalSchema($id); $queries = $persistence->getPlatForm()->getMigrateSchemaSql($fromSchema, $schema); foreach ($queries as $query) { $persistence->exec($query); } } } /** * Add the schema of a single service, if needed */ public function applySchemaProvider($service): void { if ($service instanceof SchemaProviderInterface) { $schemaCollection = $this->getSqlSchemas(); $service->provideSchema($schemaCollection); $this->applySchemas($schemaCollection); $this->logInfo('Applied schema for ' . get_class($service)); } else { $this->logDebug('No schema found for ' . get_class($service)); } } private function getDriverConfigFeeder(): ?DriverConfigurationFeeder { /** * This class is directly instantiated directly in some installation process, so the ServiceLocator * might not be available, therefore this if is necessary. */ if (!$this->getServiceLocator()) { return null; } try { return $this->getServiceLocator()->get(DriverConfigurationFeeder::SERVICE_ID); } catch (ServiceNotFoundException $exception) { /** * This is because PersistenceManager is registered in tao-core and while doing the generis update * before the update of tao (which had this class in the migrations). */ return null; } } }