Skip to content

Instantly share code, notes, and snippets.

@Kaapiii
Last active June 9, 2017 14:39
Show Gist options
  • Save Kaapiii/1d681cde297563d9c426f2366beb4c4b to your computer and use it in GitHub Desktop.
Save Kaapiii/1d681cde297563d9c426f2366beb4c4b to your computer and use it in GitHub Desktop.
Concrete5 - use a single EntityManager in version 5.7.5.6
<?php
// store location: application/src/Database
// Override the Core DatabaseServiceProvider
return array(
/**
* Core Providers
*/
'providers' => array(
'core_database' => '\Application\Src\Database\DatabaseServiceProvider',
)
);
<?php
namespace Application\Src\Database;
// store location: application/config
use Concrete\Core\Application\Application;
use Concrete\Core\Cache\Adapter\DoctrineCacheDriver;
use Concrete\Core\Database\Connection\Connection;
use Concrete\Core\Package\Package;
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Config;
use Database;
use Events;
class DatabaseManagerORM extends \Concrete\Core\Database\DatabaseManagerORM
{
/**
* Makes a new entity manager instance for the given context
* (e.g. a package) or if no context object is given, for the application
* context. The options for the context are:
* - A package object, results in a package specific entity manager
* - The string 'core', results in a core specific entity manager
* - Null or omitted context, results in an application specific entity
* manager
*
* @param Connection $connection
* @param mixed $context
* @return \Doctrine\ORM\EntityManager
*/
public static function makeEntityManager(Connection $connection, $context = null)
{
if (is_object($context) && $context instanceof Package) {
$factory = $context->getEntityManagerFactory();
} else {
if ($context === 'core') {
$path = DIR_BASE_CORE . '/' . DIRNAME_CLASSES;
//$factory = new EntityManagerFactory($path, $context);
} else {
$path = DIR_APPLICATION . '/' . DIRNAME_CLASSES;
}
$factory = new \Application\Src\Database\EntityManagerFactory($path, $context);
}
return $factory->create($connection);
}
}
<?php
namespace Application\Src\Database;
// store location: application/src/Database
use Concrete\Core\Database\Connection\ConnectionFactory;
use Concrete\Core\Database\Driver\DriverManager;
use Concrete\Core\Foundation\Service\Provider as ServiceProvider;
class DatabaseServiceProvider extends ServiceProvider
{
public function register()
{
// Make both managers singletons
$this->app->singleton('Concrete\Core\Database\DatabaseManager');
$this->app->singleton('Concrete\Core\Database\DatabaseManagerORM');
// Bind both `database` and `database/orm` to their respective classes
$this->app->bind('database', 'Concrete\Core\Database\DatabaseManager');
$this->app->bind('database/orm', '\Application\Src\Database\DatabaseManagerORM');
// Bind a constructor for our DriverManager bootstrapped from config
$this->app->bind('Concrete\Core\Database\Driver\DriverManager', function ($app) {
$manager = new DriverManager($app);
$manager->configExtensions($app->make('config')->get('database.drivers'));
return $manager;
});
// Bind a closure to support \Core::make('database/structure', $em);
$this->app->bind('database/structure', function ($app, $em) {
if (!is_array($em)) {
$em = array($em);
}
return $app->make('Concrete\Core\Database\DatabaseStructureManager', $em);
});
// Bind default entity manager resolver
$this->app->bind('Doctrine\ORM\EntityManagerInterface', function ($app) {
return $app->make('Concrete\Core\Database\DatabaseManagerORM')->entityManager();
});
$this->app->bind('Doctrine\ORM\EntityManager', 'Doctrine\ORM\EntityManagerInterface');
// Bind default connection resolver
$this->app->bind('Concrete\Core\Database\Connection\Connection', function ($app) {
return $app->make('Concrete\Core\Database\DatabaseManager')->connection();
});
$this->app->bind('Doctrine\DBAL\Connection', 'Concrete\Core\Database\Connection\Connection');
}
}
<?php
namespace Application\Src\Database;
// store location: application/src/Database
use Doctrine\ORM\EntityManager;
use Doctrine\ORM\Tools\Setup;
use Config;
use Database;
use Events;
/**
* EntityManagerFactory
*
* @author markus.liechti <[email protected]>
*/
class EntityManagerFactory implements \Concrete\Core\Database\EntityManagerFactoryInterface{
/**
* Create Application Specific EntityManager
*
* @param \Concrete\Core\Database\Connection\Connection $connection
* @return type
*/
public function create(\Concrete\Core\Database\Connection\Connection $connection) {
$args = isset($_SERVER['argv']) ? $_SERVER['argv'] : null;
$environments = require DIR_APPLICATION . '/bootstrap/environments.php';
$detector = new \Concrete\Core\Foundation\EnvironmentDetector();
$env = $detector->detect($environments, $args);
if($env == 'production'){
$cache = new \Concrete\Core\Cache\Adapter\DoctrineCacheDriver('cache/expensive');
}else{
$cache = new \Doctrine\Common\Cache\ArrayCache();
}
$config = \Doctrine\ORM\Tools\Setup::createConfiguration(
Config::get('concrete.cache.doctrine_dev_mode'),
Config::get('database.proxy_classes'),
$cache
);
// Handling the automated creation of proxies
/*if($env == 'production'){
$config->setAutoGenerateProxyClasses(false);
}else{
$config->setAutoGenerateProxyClasses(true);
}*/
// Customized
$path = DIR_APPLICATION . '/' . DIRNAME_CLASSES;
if ($context instanceof Package) {
$path = $context->getPackageEntitiesPath();
} elseif ($context === 'core') {
$path = DIR_BASE_CORE . '/' . DIRNAME_CLASSES;
} elseif (is_object($context) && method_exists($context, 'getEntitiesPath')) {
$path = $context->getEntitiesPath();
}
// Register the doctrine Annotations
\Doctrine\Common\Annotations\AnnotationRegistry::registerFile(DIR_BASE_CORE . '/vendor/doctrine/orm/lib/Doctrine/ORM' .'/Mapping/Driver/DoctrineAnnotations.php');
\Doctrine\Common\Annotations\AnnotationRegistry::registerAutoloadNamespace('Application\Src', DIR_BASE.'/application/src');
// Create manualy the next function $config->newDefaultAnnotationDriver()
// To get a instance of the cached AnnotationReader
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('package');
$annotationReader = new \Doctrine\Common\Annotations\AnnotationReader();
// Ignore the Annotions of the SimpleAnnotationReader
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('Id');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('Table');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('Column');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('GeneratedValue');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('Entity');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('OneToMany');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('ManyToOne');
\Doctrine\Common\Annotations\AnnotationReader::addGlobalIgnoredName('JoinColumn');
//@todo add some more possible annotions
// add different annotations to the ignoreing list
$cachedAnnotationReader = new \Doctrine\Common\Annotations\CachedReader($annotationReader, new \Doctrine\Common\Cache\ArrayCache());
$driverChain = new \Doctrine\Common\Persistence\Mapping\Driver\MappingDriverChain();
// Register Concrete5 customized classes in application with YamlDriver
$yamlDir = DIR_CONFIG_SITE.DIRECTORY_SEPARATOR.'yaml';
$yamlDriver = new \Doctrine\ORM\Mapping\Driver\YamlDriver($yamlDir);
$driverChain->addDriver($yamlDriver, 'Application\Src');
// Legacy
// Collect Mapping Info of the Concrete5 core wiht the simple annotation reader and add it to the driver chain
// You can pass multiple paths/directories as array
$reader = new \Doctrine\Common\Annotations\SimpleAnnotationReader();
$reader->addNamespace('Doctrine\ORM\Mapping');
$cachedSimpleAnnotationReader = new \Doctrine\Common\Annotations\CachedReader($reader, new \Doctrine\Common\Cache\ArrayCache());
// Acts as the main AnnotaionDriver
//$annotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($cachedAnnotationReader, DIR_BASE_CORE . '/' . DIRNAME_CLASSES);
//$driverChain->addDriver($annotationDriver, 'Concrete\Package\MyTestPackage');
// Acts as an lecay AnnotationDriver -> Annotions of the core are mapped all automatically to \Doctrine\ORM\Mapping
$simpleAnnotationDriver = new \Doctrine\ORM\Mapping\Driver\AnnotationDriver($cachedSimpleAnnotationReader, DIR_BASE_CORE . '/' . DIRNAME_CLASSES);
$driverChain->addDriver($simpleAnnotationDriver, 'Concrete\Core');
// Register Gedmo Doctrine Extensions
// 1.) AbstractMapping vs Mapping @See https://github.com/Atlantic18/DoctrineExtensions/issues/790
\Gedmo\DoctrineExtensions::registerMappingIntoDriverChainORM($driverChain, $cachedAnnotationReader);
//\Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM($driverChain, $cachedAnnotationReader);
// Inject DriverChain into the doctrine config
$config->setMetadataDriverImpl($driverChain);
// Concrete event
$event = new \Symfony\Component\EventDispatcher\GenericEvent();
$event->setArgument('connection', $connection);
$event->setArgument('context', $context);
$event->setArgument('configuration', $config);
Events::dispatch('on_entity_manager_configure', $event);
$config = $event->getArgument('configuration');
// Get EventManager
$evm = $connection->getEventManager();
// Register the needed Gedmo extensions
self::registerEvents($evm,$cachedAnnotationReader);
// Inject the ORM EventManager into the EntityManager so ORM Events
// can be triggered.
return EntityManager::create($connection, $config, $evm);
}
/**
* Add event listeners to event manager (Doctrine Behavioral Extensions)
*
* return \Doctrine\Common\EventManager
*/
protected static function registerEvents(\Doctrine\Common\EventManager $evm, \Doctrine\Common\Annotations\CachedReader $cachedAnnotationReader){
//$cachedAnnotationReader = new \Doctrine\Common\Annotations\CachedReader(new \Doctrine\Common\Annotations\AnnotationReader(), new \Doctrine\Common\Cache\ArrayCache());
// Sluggable
$sluggableListener = new \Gedmo\Sluggable\SluggableListener();
$sluggableListener->setAnnotationReader($cachedAnnotationReader);
// Register custom Sluggifiers (Replace Special Characters)
$callable = array('\Application\Src\Product\Model\Event\Transliterator', 'replaceSecialSigns');
$sluggableListener->setTransliterator($callable);
$evm->addEventSubscriber($sluggableListener);
// Tree
$treeListener = new \Gedmo\Tree\TreeListener();
$treeListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($treeListener);
// Timestampable
$timestampableListener = new \Gedmo\Timestampable\TimestampableListener();
$timestampableListener->setAnnotationReader($cachedAnnotationReader);
// The issue is here with SimpleAnnotationReader for Concrete and AnnotationReader for Gedmo
$evm->addEventSubscriber($timestampableListener);
// Blameable
$blameableListener = new \Gedmo\Blameable\BlameableListener();
$blameableListener->setAnnotationReader($cachedAnnotationReader);
$user = new \Concrete\Core\User\User();
if($user){
$blameableListener->setUserValue($user->getUserID());
}
$evm->addEventSubscriber($blameableListener);
// Translatable
$translatableListener = new \Gedmo\Translatable\TranslatableListener();
$translatableListener->setAnnotationReader($cachedAnnotationReader);
// Get Concrete5 default locale
//$locale = \Localization::activeLocale(); // -> example "de_DE";
//$locale = \Localization::activeLanguage(); // -> example "de";
$locale = 'de';
//$translatableListener->setTranslatableLocale($locale);
$translatableListener->setDefaultLocale($locale);
$translatableListener->setTranslationFallback(false);
//$translatableListener->setPersistDefaultLocaleTranslation(false);
$ms = \Concrete\Core\Multilingual\Page\Section\Section::getCurrentSection();
if($ms){
$locale = $ms->getLanguage();
//\Doctrine\Common\Util\Debug::dump($locale);
$translatableListener->setTranslatableLocale($locale);
}else{
//\Doctrine\Common\Util\Debug::dump($this->get('locale'));
// last fallback
$translatableListener->setTranslatableLocale('de');
// Check if locale in request is set.
$requestLocale = self::get('locale');
if(!empty($requestLocale)){
$translatableListener->setTranslatableLocale(self::get('locale'));
}
}
$evm->addEventSubscriber($translatableListener);
// Sortable
$sortableListener = new \Gedmo\Sortable\SortableListener();
$sortableListener->setAnnotationReader($cachedAnnotationReader);
$evm->addEventSubscriber($sortableListener);
}
/**
* Dublicate form the \Concrete\Core\ControllerAbstractController class
*
* Is used to place custom routes in a the mulitlingual section, so
* the correct transaltion is loaded by the gedmo translatable extension
* Example /fr/api/search/articles will triggert the content loading in english
*
* @param type $key
* @param type $defaultValue
* @return type
*/
public static function get($key = null, $defaultValue = null)
{
$sets = array();
$request = \Request::getInstance();
if ($key == null) {
return $_GET;
}
if (isset($sets[$key])) {
return $sets[$key];
}
if (!isset($request)) {
$request = \Request::createFromGlobals();
}
$val = $request->get($key, $defaultValue);
return $val;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment