├── tests └── .gitkeep ├── .gitignore ├── .travis.yml ├── provides.json ├── src ├── Doctrine2Bridge │ ├── Exception │ │ ├── Configuration.php │ │ └── ImplementationNotFound.php │ ├── Support │ │ ├── Facades │ │ │ ├── Doctrine2.php │ │ │ ├── Doctrine2Cache.php │ │ │ └── Doctrine2Repository.php │ │ └── Repository.php │ ├── Console │ │ ├── Generators │ │ │ ├── All.php │ │ │ ├── Proxies.php │ │ │ ├── Repositories.php │ │ │ └── Entities.php │ │ └── Schema │ │ │ ├── Create.php │ │ │ ├── Drop.php │ │ │ ├── Validate.php │ │ │ └── Update.php │ ├── EventListeners │ │ └── TablePrefix.php │ ├── Logger │ │ └── Laravel.php │ ├── Doctrine2CacheBridgeServiceProvider.php │ ├── Auth │ │ └── Doctrine2UserProvider.php │ ├── Utils │ │ └── JsonSerializer.php │ └── Doctrine2BridgeServiceProvider.php └── config │ ├── d2bcache.php │ └── d2bdoctrine.php ├── examples └── auth │ ├── doctrine2bridge-auth-closure.php │ ├── Entities.User.dcm.xml │ └── User.php ├── phpunit.xml ├── composer.json ├── LICENSE ├── bin └── d2b-doctrine2 └── README.md /tests/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | composer.phar 3 | composer.lock 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | 8 | before_script: 9 | - curl -s http://getcomposer.org/installer | php 10 | - php composer.phar install --dev 11 | 12 | script: phpunit -------------------------------------------------------------------------------- /provides.json: -------------------------------------------------------------------------------- 1 | { 2 | "providers": [ 3 | "Doctrine2Bridge\Doctrine2CacheBridgeServiceProvider", 4 | "Doctrine2Bridge\Doctrine2BridgeServiceProvider" 5 | ] 6 | // aliases are set uo automatically by the service providers as follows: 7 | // 8 | // D2Cache -> Doctrine2Bridge\Support\Facades\Doctrine2Cache 9 | // D2EM -> Doctrine2Bridge\Support\Facades\Doctrine2 10 | } 11 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Exception/Configuration.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 10 | * @license MIT 11 | */ 12 | class Configuration extends \Exception { 13 | 14 | public function __construct( $message = null, $code = 0, Exception $previous = null ) 15 | { 16 | return parent::__construct( 17 | $message, $code, $previous 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /examples/auth/doctrine2bridge-auth-closure.php: -------------------------------------------------------------------------------- 1 | 'doctrine2bridge' 6 | 7 | // this assumes no namespace: 8 | 9 | Auth::extend( 'doctrine2bridge', function() 10 | { 11 | return new \Illuminate\Auth\Guard( 12 | new \Doctrine2Bridge\Auth\Doctrine2UserProvider( 13 | D2EM::getRepository( '\Entities\User' ), 14 | new \Illuminate\Hashing\BcryptHasher 15 | ), 16 | App::make('session.store') 17 | ); 18 | }); 19 | 20 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Exception/ImplementationNotFound.php: -------------------------------------------------------------------------------- 1 | 9 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 10 | * @license MIT 11 | */ 12 | class ImplementationNotFound extends \Exception { 13 | 14 | public function __construct( $message = null, $code = 0, Exception $previous = null ) 15 | { 16 | return parent::__construct( 17 | "No class / implementation found for {$message}", $code, $previous 18 | ); 19 | } 20 | 21 | } 22 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Support/Facades/Doctrine2.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 13 | * @license MIT 14 | */ 15 | class Doctrine2 extends Facade { 16 | 17 | /** 18 | * Get the registered name of the component. 19 | * 20 | * @return string 21 | */ 22 | protected static function getFacadeAccessor() { return \Doctrine\ORM\EntityManagerInterface::class; } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Support/Facades/Doctrine2Cache.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 13 | * @license MIT 14 | */ 15 | class Doctrine2Cache extends Facade { 16 | 17 | /** 18 | * Get the registered name of the component. 19 | * 20 | * @return string 21 | */ 22 | protected static function getFacadeAccessor() { return \Doctrine\Common\Cache\Cache::class; } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Support/Facades/Doctrine2Repository.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 13 | * @license MIT 14 | */ 15 | class Doctrine2Repository extends Facade { 16 | 17 | /** 18 | * Get the registered name of the component. 19 | * 20 | * @return string 21 | */ 22 | protected static function getFacadeAccessor() { return '\Doctrine2Bridge\Support\Repository'; } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /examples/auth/Entities.User.dcm.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "opensolutions/doctrine2bridge-l5", 3 | "description": "Adds the the power of Doctrine2 to Laravel 5 (with support for SQL logging and authentication)", 4 | "homepage": "https://github.com/opensolutions/doctrine2bridge-l5", 5 | "keywords": [ "laravel", "doctrine2" ], 6 | "license": "MIT", 7 | "authors": [ 8 | { 9 | "name": "Barry O'Donovan", 10 | "email": "barry@opensolutions.ie", 11 | "homepage": "http://www.barryodonovan.com/", 12 | "role": "Developer" 13 | } 14 | ], 15 | "support": { 16 | "issues": "https://github.com/opensolutions/doctrine2bridge-l5/issues", 17 | "source": "https://github.com/opensolutions/doctrine2bridge-l5" 18 | }, 19 | "require": { 20 | "php": ">=5.5.0", 21 | "doctrine/orm": ">=2.4.0" 22 | }, 23 | "autoload": { 24 | "psr-0": { 25 | "Doctrine2Bridge": "src/" 26 | } 27 | }, 28 | "bin": [ "bin/d2b-doctrine2" ] 29 | } 30 | -------------------------------------------------------------------------------- /src/config/d2bcache.php: -------------------------------------------------------------------------------- 1 | 'Doctrine2', 30 | 31 | ]; 32 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Support/Repository.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 14 | * @license MIT 15 | */ 16 | class Repository { 17 | 18 | /** 19 | * The entity manager 20 | */ 21 | private $d2em = null; 22 | 23 | public function __construct( \Doctrine\ORM\EntityManagerInterface $d2em ) 24 | { 25 | $this->d2em = $d2em; 26 | } 27 | 28 | public function r( $repository, $namespace = null ) 29 | { 30 | if( $namespace == null ) { 31 | if( strpos( $repository, '\\' ) === false ) 32 | $repository = Config::get( 'd2bdoctrine.namespaces.models' ) . '\\' . $repository; 33 | } else { 34 | $repository = $namespace . '\\' . $repository; 35 | } 36 | 37 | return $this->d2em->getRepository( $repository ); 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Open Source Solutions Limited 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Generators/All.php: -------------------------------------------------------------------------------- 1 | 19 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 20 | * @license MIT 21 | */ 22 | class All extends LaravelCommand 23 | { 24 | /** 25 | * The console command name. 26 | * 27 | * @var string 28 | */ 29 | protected $name = 'd2b:generate:all'; 30 | 31 | /** 32 | * The console command description. 33 | * 34 | * @var string 35 | */ 36 | protected $description = 'Generate all Doctrine2 entities, proxies and repositoies'; 37 | 38 | public function fire() 39 | { 40 | $this->call( 'd2b:generate:entities' ); 41 | $this->call( 'd2b:generate:proxies' ); 42 | $this->call( 'd2b:generate:repositories' ); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/EventListeners/TablePrefix.php: -------------------------------------------------------------------------------- 1 | 12 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 13 | * @license MIT 14 | * 15 | * From https://github.com/mitchellvanw/laravel-doctrine/tree/master/src/EventListeners (MIT) 16 | */ 17 | class TablePrefix 18 | { 19 | protected $prefix = ''; 20 | 21 | /** 22 | * __construct 23 | * 24 | * @param string $prefix 25 | */ 26 | public function __construct($prefix) 27 | { 28 | $this->prefix = (string) $prefix; 29 | } 30 | 31 | /** 32 | * loadClassMetadata 33 | * 34 | * @link http://doctrine-orm.readthedocs.org/en/latest/cookbook/sql-table-prefixes.html 35 | * @param LoadClassMetadataEventArgs $eventArgs 36 | */ 37 | public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) 38 | { 39 | $classMetadata = $eventArgs->getClassMetadata(); 40 | $classMetadata->setTableName($this->prefix . $classMetadata->getTableName()); 41 | //if we use sequences, also prefix the sequence name 42 | if($classMetadata->isIdGeneratorSequence()) { 43 | $sequenceDefinition = $classMetadata->sequenceGeneratorDefinition; 44 | $sequenceDefinition['sequenceName'] = $this->prefix . $sequenceDefinition['sequenceName']; 45 | $classMetadata->setSequenceGeneratorDefinition($sequenceDefinition); 46 | } 47 | foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { 48 | if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY) { 49 | $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name']; 50 | $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName; 51 | } 52 | } 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /src/config/d2bdoctrine.php: -------------------------------------------------------------------------------- 1 | array( 20 | 'models' => app()->databasePath(), // entity namespace added by default 21 | 'proxies' => app()->databasePath() . '/Proxies', 22 | 'repositories' => app()->databasePath(), // repository namespace added by default 23 | 'xml_schema' => app()->databasePath() . '/xml' 24 | ), 25 | 26 | // set to true to have Doctrine2 generate proxies on the fly. Not recommended in a production system. 27 | 'autogen_proxies' => env('APP_DEBUG'), 28 | 29 | // Namespaces for entities, proxies and repositories. 30 | 'namespaces' => array( 31 | 'models' => 'Entities', 32 | 'proxies' => 'Proxies', 33 | 'repositories' => 'Repositories' 34 | ), 35 | 36 | // Doctrine2Bridge includes an implementation of Doctrine\DBAL\Logging\SQLLogger which 37 | // just calls the Laravel Log facade. If you wish to log your SQL queries (and execution 38 | // time), just set enabled in the following to true. 39 | 'sqllogger' => array( 40 | 'enabled' => env('APP_DEBUG'), 41 | 'level' => 'debug' // one of debug, info, notice, warning, error, critical, alert 42 | ), 43 | 44 | // use Doctrine2bridge with Laravel's authentication menchanism 45 | // see: https://github.com/opensolutions/doctrine2bridge/wiki/Auth 46 | 'auth' => array( 47 | 'enabled' => false, 48 | 'entity' => '\Entities\User' // the Doctrine2 entity representing the user 49 | ) 50 | ]; 51 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Logger/Laravel.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 8 | * @license MIT 9 | */ 10 | 11 | namespace Doctrine2Bridge\Logger; 12 | 13 | /** 14 | * Includes executed SQLs in a Debug Stack. 15 | * 16 | * @link www.doctrine-project.org 17 | * @since 2.0 18 | * @author Benjamin Eberlei 19 | * @author Guilherme Blanco 20 | * @author Jonathan Wage 21 | * @author Roman Borschel 22 | */ 23 | class Laravel implements \Doctrine\DBAL\Logging\SQLLogger 24 | { 25 | /** 26 | * If the logger is enabled (log queries) or not. 27 | * 28 | * @var boolean 29 | */ 30 | public $enabled = true; 31 | 32 | /** 33 | * For timing queries: 34 | * @var float|null 35 | */ 36 | public $start = null; 37 | 38 | /** 39 | * Query 40 | */ 41 | public $query = null; 42 | 43 | /** 44 | * Logging level. 45 | * 46 | * Available: debug, info, notice, warning, error, critical, and alert 47 | * 48 | * @see http://laravel.com/docs/errors#logging 49 | */ 50 | public $level = 'debug'; 51 | 52 | /** 53 | * {@inheritdoc} 54 | */ 55 | public function startQuery($sql, array $params = null, array $types = null) 56 | { 57 | if( $this->enabled ) 58 | { 59 | $this->start = microtime(true); 60 | 61 | $this->query = array( 'sql' => $sql, 'params' => $params, 'types' => $types ); 62 | } 63 | } 64 | 65 | /** 66 | * {@inheritdoc} 67 | */ 68 | public function stopQuery() 69 | { 70 | if( $this->enabled ) 71 | { 72 | $level = $this->level; 73 | 74 | \Log::$level( 75 | 'D2 SQL: ' 76 | . $this->query['sql'] 77 | . " [Executed in " . ( microtime(true) - $this->start ) . "secs.] ", 78 | array( 'params' => $this->query['params'], 'types' => $this->query['types'] ) 79 | ); 80 | } 81 | } 82 | 83 | /** 84 | * Set the debugging level 85 | * 86 | * @param string $level One of: debug, info, notice, warning, error, critical, and alert 87 | */ 88 | public function setLevel( $level ) 89 | { 90 | $this->level = $level; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Schema/Create.php: -------------------------------------------------------------------------------- 1 | 21 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 22 | * @license MIT 23 | */ 24 | class Create extends LaravelCommand 25 | { 26 | /** 27 | * The console command name. 28 | * 29 | * @var string 30 | */ 31 | protected $name = 'd2b:schema:create'; 32 | 33 | /** 34 | * The console command description. 35 | * 36 | * @var string 37 | */ 38 | protected $description = 'Create the database schema from models'; 39 | 40 | 41 | /** 42 | * The schema tool. 43 | * 44 | * @var \Doctrine\ORM\Tools\SchemaTool 45 | */ 46 | private $tool; 47 | 48 | /** 49 | * The class metadata factory 50 | * 51 | * @var \Doctrine\ORM\Tools\SchemaTool 52 | */ 53 | private $metadata; 54 | 55 | public function __construct(SchemaTool $tool, ClassMetadataFactory $metadata) 56 | { 57 | parent::__construct(); 58 | $this->tool = $tool; 59 | $this->metadata = $metadata; 60 | } 61 | 62 | 63 | public function fire() 64 | { 65 | if( $this->option('sql') ) { 66 | $this->info('Outputting create query:' . PHP_EOL); 67 | 68 | $sql = $this->tool->getCreateSchemaSql($this->metadata->getAllMetadata()); 69 | $this->info(implode(';'.PHP_EOL, $sql) . ';'); 70 | 71 | } else if( $this->option('commit') ) { 72 | $this->info('Creating database schema...'); 73 | $this->tool->createSchema($this->metadata->getAllMetadata()); 74 | $this->info('Schema has been created!'); 75 | } else { 76 | $this->comment( "Warning: this command can cause data loss. Run with --sql or --commit." ); 77 | } 78 | } 79 | 80 | protected function getOptions() 81 | { 82 | return [ 83 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute creation.'], 84 | ['commit', false, InputOption::VALUE_NONE, 'Executes database schema creation.'] 85 | ]; 86 | } 87 | 88 | } 89 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Schema/Drop.php: -------------------------------------------------------------------------------- 1 | 21 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 22 | * @license MIT 23 | */ 24 | class Drop extends LaravelCommand 25 | { 26 | /** 27 | * The console command name. 28 | * 29 | * @var string 30 | */ 31 | protected $name = 'd2b:schema:drop'; 32 | 33 | /** 34 | * The console command description. 35 | * 36 | * @var string 37 | */ 38 | protected $description = 'Drop the database schema'; 39 | 40 | 41 | /** 42 | * The schema tool. 43 | * 44 | * @var \Doctrine\ORM\Tools\SchemaTool 45 | */ 46 | private $tool; 47 | 48 | /** 49 | * The class metadata factory 50 | * 51 | * @var \Doctrine\ORM\Tools\SchemaTool 52 | */ 53 | private $metadata; 54 | 55 | public function __construct(SchemaTool $tool, ClassMetadataFactory $metadata) 56 | { 57 | parent::__construct(); 58 | $this->tool = $tool; 59 | $this->metadata = $metadata; 60 | } 61 | 62 | 63 | public function fire() 64 | { 65 | $sql = $this->tool->getDropSchemaSQL($this->metadata->getAllMetadata()); 66 | 67 | if( empty($sql) ) { 68 | $this->error('Current models do not exist in schema.'); 69 | return; 70 | } 71 | 72 | if( $this->option('sql') ) { 73 | $this->info('Outputting drop query:'.PHP_EOL); 74 | $this->line(implode(';' . PHP_EOL, $sql) . ';'); 75 | } else if( $this->option('commit') ) { 76 | $this->info('Dropping database schema....'); 77 | $this->tool->dropSchema($this->metadata->getAllMetadata()); 78 | $this->info('Schema has been dropped!'); 79 | } else { 80 | $this->comment( "Warning: this command can cause data loss. Run with --sql or --commit." ); 81 | } 82 | } 83 | 84 | protected function getOptions() 85 | { 86 | return [ 87 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute drop.'], 88 | ['commit', false, InputOption::VALUE_NONE, 'Executes database schema drop.'] 89 | ]; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /bin/d2b-doctrine2: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | 8 | * @copyright Copyright (c) 2014 Open Source Solutions Limited 9 | * @license MIT 10 | */ 11 | 12 | 13 | mb_internal_encoding('UTF-8'); 14 | mb_language('uni'); 15 | 16 | require __DIR__.'/../../../../bootstrap/autoload.php'; 17 | $app = require_once __DIR__.'/../../../../bootstrap/app.php'; 18 | $kernel = $app->make('Illuminate\Contracts\Console\Kernel'); 19 | $kernel->bootstrap(); 20 | 21 | use Symfony\Component\Console\Helper\DialogHelper; 22 | use Symfony\Component\Console\Helper\HelperSet; 23 | use Doctrine\DBAL\Tools\Console\Helper\ConnectionHelper; 24 | use Doctrine\ORM\Tools\Console\Helper\EntityManagerHelper; 25 | use Doctrine\ORM\Tools\Console\ConsoleRunner; 26 | 27 | use Doctrine\DBAL\Migrations\Configuration\Configuration; 28 | use Doctrine\DBAL\Migrations\Tools\Console\Command\DiffCommand; 29 | use Doctrine\DBAL\Migrations\Tools\Console\Command\ExecuteCommand; 30 | use Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand; 31 | use Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand; 32 | use Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand; 33 | use Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand; 34 | 35 | $d2cache = $app->make( Doctrine\Common\Cache\Cache::class ); 36 | $d2em = $app->make( Doctrine\ORM\EntityManagerInterface::class ); 37 | 38 | $helperSet = new HelperSet( array( 39 | 'db' => new ConnectionHelper( $d2em->getConnection() ), 40 | 'em' => new EntityManagerHelper( $d2em ), 41 | 'dialog' => new DialogHelper(), 42 | )); 43 | 44 | $cli = new \Symfony\Component\Console\Application( 'Doctrine Command Line Interface', Doctrine\Common\Version::VERSION ); 45 | $cli->setCatchExceptions(true); 46 | 47 | // from http://docs.doctrine-project.org/projects/doctrine-migrations/en/latest/reference/introduction.html 48 | $cli->addCommands( array( 49 | // Migrations Commands 50 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\DiffCommand(), 51 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\ExecuteCommand(), 52 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\GenerateCommand(), 53 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\MigrateCommand(), 54 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\StatusCommand(), 55 | new \Doctrine\DBAL\Migrations\Tools\Console\Command\VersionCommand() 56 | )); 57 | 58 | Doctrine\ORM\Tools\Console\ConsoleRunner::addCommands( $cli ); 59 | 60 | $helpers = $cli->getHelperSet(); 61 | foreach ($helperSet as $name => $helper) { 62 | $helpers->set($helper, $name); 63 | } 64 | 65 | D2Cache::flushAll(); 66 | 67 | $cli->run(); 68 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Generators/Proxies.php: -------------------------------------------------------------------------------- 1 | 22 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 23 | * @license MIT 24 | */ 25 | class Proxies extends LaravelCommand 26 | { 27 | /** 28 | * The console command name. 29 | * 30 | * @var string 31 | */ 32 | protected $name = 'd2b:generate:proxies'; 33 | 34 | /** 35 | * The console command description. 36 | * 37 | * @var string 38 | */ 39 | protected $description = 'Generate Doctrine2 proxies for entities.'; 40 | 41 | /** 42 | * The Entity Manager 43 | * 44 | * @var \Doctrine\ORM\EntityManagerInterface 45 | */ 46 | private $d2em; 47 | 48 | public function __construct(\Doctrine\ORM\EntityManagerInterface $d2em) 49 | { 50 | parent::__construct(); 51 | 52 | $this->d2em = $d2em; 53 | } 54 | 55 | public function fire() 56 | { 57 | $this->info('Starting proxy generation....'); 58 | 59 | // flush all generated and cached entities, etc 60 | \D2Cache::flushAll(); 61 | 62 | try { 63 | $metadata = $this->d2em->getMetadataFactory()->getAllMetadata(); 64 | } catch( \Doctrine\Common\Persistence\Mapping\MappingException $e ) { 65 | if( $this->option( 'verbose' ) == 3 ) 66 | throw $e; 67 | 68 | $this->error( "Caught Doctrine\Common\Persistence\Mapping\MappingException: " . $e->getMessage() ); 69 | $this->info( "Re-optimizing:" ); 70 | $this->call( 'optimize' ); 71 | $this->comment( "*** You must now rerun this artisan command ***" ); 72 | exit(-1); 73 | } 74 | 75 | if( empty($metadata) ) { 76 | $this->error('No metadata found to generate entities.'); 77 | return -1; 78 | } 79 | 80 | $directory = Config::get( 'd2bdoctrine.paths.proxies' ); 81 | 82 | if( !$directory ) { 83 | $this->error('The proxy directory has not been set.'); 84 | return -1; 85 | } 86 | 87 | $this->info('Processing entities:'); 88 | foreach ($metadata as $item) { 89 | $this->line($item->name); 90 | } 91 | 92 | $this->d2em->getProxyFactory()->generateProxyClasses($metadata, $directory); 93 | $this->info('Proxies have been created.'); 94 | } 95 | 96 | } 97 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Schema/Validate.php: -------------------------------------------------------------------------------- 1 | 21 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 22 | * @license MIT 23 | */ 24 | class Validate extends LaravelCommand 25 | { 26 | /** 27 | * The console command name. 28 | * 29 | * @var string 30 | */ 31 | protected $name = 'd2b:schema:validate'; 32 | 33 | /** 34 | * The console command description. 35 | * 36 | * @var string 37 | */ 38 | protected $description = 'Validate the database schema'; 39 | 40 | public function fire( \Doctrine\ORM\EntityManagerInterface $d2em ) 41 | { 42 | $validator = new SchemaValidator($d2em); 43 | $exit = 0; 44 | 45 | if( $this->option('skip-mapping') ) 46 | { 47 | $this->comment( '[Mapping] Skipped mapping check.' ); 48 | } 49 | elseif( $errors = $validator->validateMapping() ) 50 | { 51 | foreach( $errors as $className => $errorMessages ) 52 | { 53 | $this->error( "[Mapping] FAIL - The entity-class '" . $className . "' mapping is invalid:" ); 54 | 55 | foreach( $errorMessages as $errorMessage ) { 56 | $this->line( '* ' . $errorMessage ); 57 | } 58 | 59 | $this->line(); 60 | } 61 | 62 | $exit += 1; 63 | } 64 | else 65 | { 66 | $this->info( "[Mapping] OK - The mapping files are correct." ); 67 | } 68 | 69 | if( $this->option( 'skip-sync' ) ) 70 | { 71 | $this->comment( "[Database] SKIPPED - The database was not checked for synchronicity." ); 72 | } 73 | elseif( !$validator->schemaInSyncWithMetadata() ) 74 | { 75 | $this->error( "[Database] FAIL - The database schema is not in sync with the current mapping file." ); 76 | $exit += 2; 77 | } 78 | else 79 | { 80 | $this->info( "[Database] OK - The database schema is in sync with the mapping files." ); 81 | } 82 | } 83 | 84 | protected function getOptions() 85 | { 86 | return [ 87 | [ 'skip-mapping', false, InputOption::VALUE_NONE, 'Skip the mapping validation check' ], 88 | [ 'skip-sync', false, InputOption::VALUE_NONE, 'Skip checking if the mapping is in sync with the database' ], 89 | ]; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Schema/Update.php: -------------------------------------------------------------------------------- 1 | 21 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 22 | * @license MIT 23 | */ 24 | class Update extends LaravelCommand 25 | { 26 | /** 27 | * The console command name. 28 | * 29 | * @var string 30 | */ 31 | protected $name = 'd2b:schema:update'; 32 | 33 | /** 34 | * The console command description. 35 | * 36 | * @var string 37 | */ 38 | protected $description = 'Update the database schema'; 39 | 40 | 41 | /** 42 | * The schema tool. 43 | * 44 | * @var \Doctrine\ORM\Tools\SchemaTool 45 | */ 46 | private $tool; 47 | 48 | /** 49 | * The class metadata factory 50 | * 51 | * @var \Doctrine\ORM\Tools\SchemaTool 52 | */ 53 | private $metadata; 54 | 55 | public function __construct(SchemaTool $tool, ClassMetadataFactory $metadata) 56 | { 57 | parent::__construct(); 58 | $this->tool = $tool; 59 | $this->metadata = $metadata; 60 | } 61 | 62 | 63 | public function fire() 64 | { 65 | 66 | $this->info('Checking if database needs updating....'); 67 | 68 | $sql = $this->tool->getUpdateSchemaSql( $this->metadata->getAllMetadata(), $this->option('clean') ); 69 | 70 | if( empty($sql) ) { 71 | $this->info('No updates found.'); 72 | return; 73 | } 74 | 75 | if( $this->option( 'sql' ) ) { 76 | $this->info('Outputting update query:'); 77 | $this->info(implode(';' . PHP_EOL, $sql) .';'); 78 | } else if( $this->option( 'commit' ) ) { 79 | $this->info('Updating database schema....'); 80 | $this->tool->updateSchema($this->metadata->getAllMetadata()); 81 | $this->info('Schema has been updated!'); 82 | } else { 83 | $this->comment( "Warning: this command can cause data loss. Run with --sql or --commit." ); 84 | } 85 | } 86 | 87 | protected function getOptions() 88 | { 89 | return [ 90 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute creation.'], 91 | ['commit', false, InputOption::VALUE_NONE, 'Executes database schema creation.'], 92 | ['clean', null, InputOption::VALUE_OPTIONAL, 'When using clean, models all non-relevant to current metadata will be cleared.'] 93 | 94 | ]; 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /examples/auth/User.php: -------------------------------------------------------------------------------- 1 | username = $username; 36 | 37 | return $this; 38 | } 39 | 40 | /** 41 | * Get username 42 | * 43 | * @return string 44 | */ 45 | public function getUsername() 46 | { 47 | return $this->username; 48 | } 49 | 50 | /** 51 | * Set password 52 | * 53 | * @param string $password 54 | * 55 | * @return User 56 | */ 57 | public function setPassword($password) 58 | { 59 | $this->password = $password; 60 | 61 | return $this; 62 | } 63 | 64 | /** 65 | * Get password 66 | * 67 | * @return string 68 | */ 69 | public function getPassword() 70 | { 71 | return $this->password; 72 | } 73 | 74 | /** 75 | * Get id 76 | * 77 | * @return integer 78 | */ 79 | public function getId() 80 | { 81 | return $this->id; 82 | } 83 | 84 | 85 | 86 | /** 87 | * Get the unique identifier for the user. 88 | * 89 | * Required as we implement `\Illuminate\Auth\UserInterface` 90 | * 91 | * @return mixed 92 | */ 93 | public function getAuthIdentifier() 94 | { 95 | return $this->getId(); 96 | } 97 | 98 | /** 99 | * Get the password for the user. 100 | * 101 | * Required as we implement `\Illuminate\Auth\UserInterface` 102 | * 103 | * @return string 104 | */ 105 | public function getAuthPassword() 106 | { 107 | return $this->getPassword(); 108 | } 109 | 110 | 111 | /** 112 | * Get the token value for the "remember me" session. 113 | * 114 | * @return string 115 | */ 116 | public function getRememberToken() 117 | { 118 | return $this->remember_token; 119 | } 120 | 121 | /** 122 | * Set the token value for the "remember me" session. 123 | * 124 | * @param string $value 125 | * @return void 126 | */ 127 | public function setRememberToken($value) 128 | { 129 | $this->remember_token = $value; 130 | } 131 | 132 | /** 133 | * Get the column name for the "remember me" token. 134 | * 135 | * @return string 136 | */ 137 | public function getRememberTokenName() 138 | { 139 | return 'remember_token'; 140 | } 141 | 142 | 143 | } 144 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Generators/Repositories.php: -------------------------------------------------------------------------------- 1 | 26 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 27 | * @license MIT 28 | */ 29 | class Repositories extends LaravelCommand 30 | { 31 | /** 32 | * The console command name. 33 | * 34 | * @var string 35 | */ 36 | protected $name = 'd2b:generate:repositories'; 37 | 38 | /** 39 | * The console command description. 40 | * 41 | * @var string 42 | */ 43 | protected $description = 'Generate Doctrine2 repositories for the entities'; 44 | 45 | /** 46 | * The Entity Manager 47 | * 48 | * @var \Doctrine\ORM\EntityManagerInterface 49 | */ 50 | private $d2em; 51 | 52 | public function __construct(\Doctrine\ORM\EntityManagerInterface $d2em) 53 | { 54 | parent::__construct(); 55 | 56 | $this->d2em = $d2em; 57 | } 58 | 59 | public function fire() 60 | { 61 | $this->info('Starting repository generation....'); 62 | 63 | // flush all generated and cached entities, etc 64 | \D2Cache::flushAll(); 65 | 66 | try { 67 | $metadatas = $this->d2em->getMetadataFactory()->getAllMetadata(); 68 | } catch( \Doctrine\Common\Persistence\Mapping\MappingException $e ) { 69 | if( $this->option( 'verbose' ) == 3 ) 70 | throw $e; 71 | 72 | $this->error( "Caught Doctrine\Common\Persistence\Mapping\MappingException: " . $e->getMessage() ); 73 | 74 | $this->info( "Re-optimizing:" ); 75 | $this->call( 'optimize' ); 76 | $this->comment( "*** You must now rerun this artisan command ***" ); 77 | exit(-1); 78 | } 79 | 80 | if( empty($metadatas) ) { 81 | $this->error('No metadata found to generate entities.'); 82 | return -1; 83 | } 84 | 85 | $directory = Config::get( 'd2bdoctrine.paths.repositories' ); 86 | 87 | if( !$directory ) { 88 | $this->error('The entity directory has not been set.'); 89 | return -1; 90 | } 91 | 92 | $numRepositories = 0; 93 | $generator = new EntityRepositoryGenerator(); 94 | 95 | foreach ($metadatas as $metadata) { 96 | if ($metadata->customRepositoryClassName) { 97 | $this->line( sprintf('Processing repository "%s"', $metadata->customRepositoryClassName) ); 98 | $generator->writeEntityRepositoryClass($metadata->customRepositoryClassName, $directory); 99 | $numRepositories++; 100 | } 101 | } 102 | 103 | if ($numRepositories) { 104 | $this->info( 'Repositories have been created.'); 105 | } else { 106 | $this->info('No Repository classes were found to be processed.' ); 107 | } 108 | } 109 | 110 | } 111 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Doctrine2CacheBridgeServiceProvider.php: -------------------------------------------------------------------------------- 1 | 13 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 14 | * @license MIT 15 | */ 16 | class Doctrine2CacheBridgeServiceProvider extends \Illuminate\Support\ServiceProvider 17 | { 18 | 19 | /** 20 | * Bootstrap the application events. 21 | * 22 | * @return void 23 | */ 24 | public function boot() 25 | { 26 | // handle the publishing of configuration file 27 | $this->handleConfigs(); 28 | } 29 | 30 | 31 | /** 32 | * Register the service provider. 33 | * 34 | * @return void 35 | */ 36 | public function register() 37 | { 38 | $this->registerCache(); 39 | 40 | // Shortcut so developers don't need to add an Alias in app/config/app.php 41 | \App::booting( function() { 42 | $loader = \Illuminate\Foundation\AliasLoader::getInstance(); 43 | $loader->alias( 'D2Cache', 'Doctrine2Bridge\Support\Facades\Doctrine2Cache' ); 44 | }); 45 | 46 | } 47 | 48 | 49 | private function registerCache() 50 | { 51 | $this->app->singleton( Cache::class, function ($app) { 52 | 53 | $config = $this->laravelToDoctrineConfigMapper(); 54 | 55 | $cacheClass = "\Doctrine\Common\Cache\\" . $config['type']; 56 | 57 | if(!class_exists($cacheClass)) 58 | throw new Exception\ImplementationNotFound( $cacheClass ); 59 | 60 | switch( $config['type'] ) 61 | { 62 | case 'ArrayCache': 63 | $cache = new $cacheClass(); 64 | break; 65 | 66 | case 'FilesystemCache': 67 | $cache = new $cacheClass( $config['dir'] ); 68 | break; 69 | 70 | case 'MemcacheCache': 71 | $cache = new $cacheClass; 72 | $cache->setMemcache( $this->setupMemcache( $config ) ); 73 | break; 74 | } 75 | 76 | if( Config::has( 'd2bcache.namespace') ) 77 | $cache->setNamespace( Config::get( 'd2bcache.namespace') ); 78 | 79 | return $cache; 80 | }); 81 | } 82 | 83 | /** 84 | * Setup the standard PHP memcache object implementation 85 | */ 86 | private function setupMemcache( $config ) 87 | { 88 | $memcache = new \Memcache; 89 | 90 | if( !isset( $config['servers'] ) || !count( $config['servers'] ) ) 91 | throw new Exception\Configuration( 'No servers defined for Memcache in config/cache.php' ); 92 | 93 | foreach( $config['servers'] as $server ) 94 | { 95 | $memcache->addServer( 96 | $server['host'], 97 | isset( $server['port'] ) ? $server['port'] : 11211, 98 | isset( $server['persistent'] ) ? $server['persistent'] : false, 99 | isset( $server['weight'] ) ? $server['weight'] : 1, 100 | isset( $server['timeout'] ) ? $server['timeout'] : 1, 101 | isset( $server['retry_int'] ) ? $server['retry_int'] : 15 102 | ); 103 | } 104 | 105 | return $memcache; 106 | } 107 | 108 | /** 109 | * Publish the configuration file 110 | */ 111 | private function handleConfigs() { 112 | $configPath = __DIR__ . '/../config/d2bcache.php'; 113 | $this->publishes( [ $configPath => config_path('d2bcache.php') ] ); 114 | $this->mergeConfigFrom( $configPath, 'd2bcache' ); 115 | } 116 | 117 | /** 118 | * Convert Laravel5's cache configuration to something what Doctrine2's 119 | * cache providers can use. 120 | * 121 | * @return array 122 | */ 123 | private function laravelToDoctrineConfigMapper() 124 | { 125 | switch( Config::get( 'cache.default' ) ) { 126 | case 'file': 127 | return [ 128 | 'type' => 'FilesystemCache', 129 | 'dir' => Config::get( 'cache.stores.file.path' ) . DIRECTORY_SEPARATOR . 'doctine2.cache' 130 | ]; 131 | break; 132 | 133 | case 'array': 134 | return [ 135 | 'type' => 'ArrayCache', 136 | ]; 137 | break; 138 | 139 | case 'memcached': 140 | return [ 141 | 'type' => 'MemcacheCache', 142 | 'servers' => Config::get( 'cache.stores.memcached.servers' ) 143 | ]; 144 | break; 145 | 146 | default: 147 | throw new Exception\ImplementationNotFound( Config::get( 'cache.default' ) ); 148 | 149 | } 150 | } 151 | 152 | } 153 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Auth/Doctrine2UserProvider.php: -------------------------------------------------------------------------------- 1 | 7 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 8 | * @license MIT 9 | */ 10 | 11 | namespace Doctrine2Bridge\Auth; 12 | 13 | /** 14 | * Class to provide a Doctrine2 user object for Laravel authentication. 15 | */ 16 | class Doctrine2UserProvider implements \Illuminate\Contracts\Auth\UserProvider 17 | { 18 | /** 19 | * The hasher implementation. 20 | * 21 | * @var \Illuminate\Hashing\HasherInterface 22 | */ 23 | protected $hasher; 24 | 25 | /** 26 | * The repository (table) containing the users. 27 | * 28 | * @var \Doctrine\ORM\EntityRepository 29 | */ 30 | protected $d2repository; 31 | 32 | /** 33 | * Create a new database user provider. 34 | * 35 | * @param \Doctrine\ORM\EntityRepository $d2repository The Doctrine2 repository (table) containing the users. 36 | * @param \Illuminate\Hashing\HasherInterface $hasher The hasher implementation 37 | * @return void 38 | */ 39 | public function __construct( \Doctrine\ORM\EntityRepository $d2repository, \Illuminate\Contracts\Hashing\Hasher $hasher ) 40 | { 41 | $this->d2repository = $d2repository; 42 | $this->hasher = $hasher; 43 | } 44 | 45 | /** 46 | * Retrieve a user by their unique identifier. 47 | * 48 | * @param mixed $identifier 49 | * @return \Illuminate\Auth\UserInterface|null 50 | */ 51 | public function retrieveById( $identifier ) 52 | { 53 | return $this->d2repository->find( $identifier ); 54 | } 55 | 56 | /** 57 | * Retrieve a user by the given credentials. 58 | * 59 | * @param array $credentials 60 | * @return \Illuminate\Auth\UserInterface|null 61 | */ 62 | public function retrieveByCredentials(array $credentials) 63 | { 64 | // First we will add each credential element to the query as a where clause. 65 | // Then we can execute the query and, if we found a user, return it in a 66 | // Doctrine2 "user" entity object that will be utilised by the Guard instances. 67 | $qb = $this->d2repository->createQueryBuilder( 'u' ) 68 | ->select( 'u' ) 69 | ->setMaxResults( 1 ); 70 | 71 | $i = 1; 72 | foreach( $credentials as $key => $value ) 73 | { 74 | if( !str_contains( $key, 'password' ) ) 75 | { 76 | $qb->andWhere( "u.{$key} = ?{$i}" ) 77 | ->setParameter( $i++, $value ); 78 | } 79 | } 80 | 81 | // Now we are ready to execute the query to see if we have an user matching 82 | // the given credentials. If not, we will just return nulls and indicate 83 | // that there are no matching users for these given credential arrays. 84 | try 85 | { 86 | return $qb->getQuery()->getSingleResult(); 87 | } 88 | catch( \Doctrine\ORM\NoResultException $e ) 89 | { 90 | return null; 91 | } 92 | } 93 | 94 | /** 95 | * Validate a user against the given credentials. 96 | * 97 | * @param \Illuminate\Auth\UserInterface $user 98 | * @param array $credentials 99 | * @return bool 100 | */ 101 | public function validateCredentials( \Illuminate\Contracts\Auth\Authenticatable $user, array $credentials ) 102 | { 103 | $plain = $credentials['password']; 104 | 105 | return $this->hasher->check( $plain, $user->getAuthPassword() ); 106 | } 107 | 108 | 109 | /** 110 | * Retrieve a user by their unique "remember me" token. 111 | * 112 | * @param mixed $identifier 113 | * @param string $token 114 | * @return \Illuminate\Auth\UserInterface|null 115 | */ 116 | public function retrieveByToken( $identifier, $token ) 117 | { 118 | try { 119 | return $this->d2repository 120 | ->createQueryBuilder( 'u' ) 121 | ->setMaxResults( 1 ) 122 | ->select( 'u' ) 123 | ->andWhere( 'u.id = :id' )->setParameter( 'id', $identifier ) 124 | ->andWhere( 'u.remember_token = :token' )->setParameter( 'token', $token ) 125 | ->getQuery() 126 | ->getSingleResult(); 127 | } 128 | catch( \Doctrine\ORM\NoResultException $e ) { 129 | return null; 130 | } 131 | } 132 | 133 | 134 | /** 135 | * Updates the "remember me" token for the given user in storage. 136 | * 137 | * @param \Illuminate\Auth\UserInterface $user 138 | * @param string $token 139 | * @return void 140 | */ 141 | public function updateRememberToken( \Illuminate\Contracts\Auth\Authenticatable $user, $token ) 142 | { 143 | 144 | $user->setRememberToken( $token ); 145 | $this->d2repository->createQueryBuilder( 'u' )->getEntityManager()->flush(); 146 | } 147 | 148 | } 149 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Console/Generators/Entities.php: -------------------------------------------------------------------------------- 1 | 26 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 27 | * @license MIT 28 | */ 29 | class Entities extends LaravelCommand 30 | { 31 | /** 32 | * The console command name. 33 | * 34 | * @var string 35 | */ 36 | protected $name = 'd2b:generate:entities'; 37 | 38 | /** 39 | * The console command description. 40 | * 41 | * @var string 42 | */ 43 | protected $description = 'Generate Doctrine2 entities'; 44 | 45 | /** 46 | * The Entity Manager 47 | * 48 | * @var \Doctrine\ORM\EntityManagerInterface 49 | */ 50 | private $d2em; 51 | 52 | public function __construct(\Doctrine\ORM\EntityManagerInterface $d2em) 53 | { 54 | parent::__construct(); 55 | 56 | $this->d2em = $d2em; 57 | } 58 | 59 | public function fire() 60 | { 61 | $this->info('Starting entities generation....'); 62 | 63 | // flush all generated and cached entities, etc 64 | \D2Cache::flushAll(); 65 | 66 | $cmf = new DisconnectedClassMetadataFactory(); 67 | $cmf->setEntityManager($this->d2em); 68 | $metadata = $cmf->getAllMetadata(); 69 | 70 | if( empty($metadata) ) { 71 | $this->error('No metadata found to generate entities.'); 72 | return -1; 73 | } 74 | 75 | $directory = Config::get( 'd2bdoctrine.paths.models' ); 76 | 77 | if( !$directory ) { 78 | $this->error('The entity directory has not been set.'); 79 | return -1; 80 | } 81 | 82 | $entityGenerator = new EntityGenerator(); 83 | 84 | $entityGenerator->setGenerateAnnotations($this->option('generate-annotations')); 85 | $entityGenerator->setGenerateStubMethods($this->option('generate-methods')); 86 | $entityGenerator->setRegenerateEntityIfExists($this->option('regenerate-entities')); 87 | $entityGenerator->setUpdateEntityIfExists($this->option('update-entities')); 88 | $entityGenerator->setNumSpaces($this->option('num-spaces')); 89 | $entityGenerator->setBackupExisting(!$this->option('no-backup')); 90 | 91 | $this->info('Processing entities:'); 92 | foreach ($metadata as $item) { 93 | $this->line($item->name); 94 | } 95 | 96 | try { 97 | $entityGenerator->generate($metadata, $directory); 98 | $this->info('Entities have been created.'); 99 | } catch ( \ErrorException $e ) { 100 | if( $this->option( 'verbose' ) == 3 ) 101 | throw $e; 102 | 103 | $this->error( "Caught ErrorException: " . $e->getMessage() ); 104 | $this->info( "Re-optimizing:" ); 105 | $this->call( 'optimize' ); 106 | $this->comment( "*** You must now rerun this artisan command ***" ); 107 | exit(-1); 108 | } 109 | } 110 | 111 | 112 | protected function getOptions() 113 | { 114 | return [ 115 | [ 116 | 'generate-annotations', null, InputOption::VALUE_OPTIONAL, 117 | 'Flag to define if generator should generate annotation metadata on entities.', false 118 | ], 119 | [ 120 | 'generate-methods', null, InputOption::VALUE_OPTIONAL, 121 | 'Flag to define if generator should generate stub methods on entities.', true 122 | ], 123 | [ 124 | 'regenerate-entities', null, InputOption::VALUE_OPTIONAL, 125 | 'Flag to define if generator should regenerate entity if it exists.', false 126 | ], 127 | [ 128 | 'update-entities', null, InputOption::VALUE_OPTIONAL, 129 | 'Flag to define if generator should only update entity if it exists.', true 130 | ], 131 | [ 132 | 'extend', null, InputOption::VALUE_REQUIRED, 133 | 'Defines a base class to be extended by generated entity classes.' 134 | ], 135 | [ 136 | 'num-spaces', null, InputOption::VALUE_REQUIRED, 137 | 'Defines the number of indentation spaces', 4 138 | ], 139 | [ 140 | 'no-backup', null, InputOption::VALUE_NONE, 141 | 'Flag to define if generator should avoid backuping existing entity file if it exists.' 142 | ] 143 | ]; 144 | } 145 | 146 | 147 | } 148 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Utils/JsonSerializer.php: -------------------------------------------------------------------------------- 1 | array(parameters) to convert 15 | * @param array $blacklist List of entity=>array(parameters) to skip 16 | * @return string 17 | */ 18 | public static function json_encode($object, $depth=1, $whitelist=array(), $blacklist=array()){ 19 | return json_encode(self::toArray($object, $depth, $whitelist, $blacklist)); 20 | } 21 | 22 | /** 23 | * Serializes our Doctrine Entities 24 | * 25 | * This is the primary entry point, because it assists with handling collections 26 | * as the primary Object 27 | * 28 | * @param object $object The Object (Typically a Doctrine Entity) to convert to an array 29 | * @param integer $depth The Depth of the object graph to pursue 30 | * @param array $whitelist List of entity=>array(parameters) to convert 31 | * @param array $blacklist List of entity=>array(parameters) to skip 32 | * @return NULL|Array 33 | * 34 | */ 35 | public static function toArray($object, $depth = 1,$whitelist=array(), $blacklist=array()){ 36 | 37 | // If we drop below depth 0, just return NULL 38 | if ($depth < 0){ 39 | return NULL; 40 | } 41 | 42 | // If this is an array, we need to loop through the values 43 | if (is_array($object)){ 44 | // Somthing to Hold Return Values 45 | $anArray = array(); 46 | 47 | // The Loop 48 | foreach ($object as $value){ 49 | // Store the results 50 | $anArray[] = self::arrayizor($value, $depth, $whitelist, $blacklist); 51 | } 52 | // Return it 53 | return $anArray; 54 | }else{ 55 | // Just return it 56 | return self::arrayizor($object, $depth, $whitelist, $blacklist); 57 | } 58 | } 59 | 60 | /** 61 | * This does all the heavy lifting of actually converting to an array 62 | * 63 | * @param object $object The Object (Typically a Doctrine Entity) to convert to an array 64 | * @param integer $depth The Depth of the object graph to pursue 65 | * @param array $whitelist List of entity=>array(parameters) to convert 66 | * @param array $blacklist List of entity=>array(parameters) to skip 67 | * @return NULL|Array 68 | */ 69 | private static function arrayizor($anObject, $depth, $whitelist=array(), $blacklist=array()){ 70 | // Determine the next depth to use 71 | $nextDepth = $depth - 1; 72 | 73 | // Lets get our Class Name 74 | // @TODO: Making some assumptions that only objects get passed in, need error checking 75 | $clazzName = get_class($anObject); 76 | 77 | // Now get our reflection class for this class name 78 | $reflectionClass = new \ReflectionClass($clazzName); 79 | 80 | // Then grap the class properites 81 | $clazzProps = $reflectionClass->getProperties(); 82 | 83 | if (is_a($anObject, 'Doctrine\ORM\Proxy\Proxy')){ 84 | $parent = $reflectionClass->getParentClass(); 85 | $clazzName = $parent->getName(); 86 | $clazzProps = $parent->getProperties(); 87 | } 88 | // A new array to hold things for us 89 | $anArray = array(); 90 | 91 | // Lets loop through those class properties now 92 | foreach ($clazzProps as $prop){ 93 | 94 | // If a Whitelist exists 95 | if (@count($whitelist[$clazzName]) > 0){ 96 | // And this class property is not in it 97 | if (! @in_array($prop->name, $whitelist[$clazzName])){ 98 | // lets skip it. 99 | continue; 100 | } 101 | // Otherwise, if a blacklist exists 102 | }elseif (@count($blacklist[$clazzName] > 0)){ 103 | // And this class property is in it 104 | if (@in_array($prop->name, $blacklist[$clazzName])){ 105 | // lets skip it. 106 | continue; 107 | } 108 | } 109 | 110 | // We know the property, lets craft a getProperty method 111 | // $method_name = 'get' . ucfirst($prop->name) ; 112 | $method_name = 'get' . preg_replace_callback( 113 | '/_[a-zA-Z]/', 114 | function ($match) { 115 | $s = $match[0]; 116 | return strtoupper($s[1]); 117 | }, 118 | ucfirst( $prop->name ) 119 | ); 120 | 121 | // And check to see that it exists for this object 122 | if (! method_exists($anObject, $method_name)){ 123 | continue; 124 | } 125 | // It did, so lets call it! 126 | $aValue = $anObject->$method_name(); 127 | 128 | // If it is an object, we need to handle that 129 | if (is_object($aValue)){ 130 | // If it is a datetime, lets make it a string 131 | if (get_class($aValue) === 'DateTime'){ 132 | $anArray[$prop->name] = $aValue->format('Y-m-d H:i:s'); 133 | 134 | // If it is a Doctrine Collection, we need to loop through it 135 | }elseif(get_class($aValue) ==='Doctrine\ORM\PersistentCollection'){ 136 | $collect = array(); 137 | foreach ($aValue as $val){ 138 | $collect[] = self::toArray($val, $nextDepth, $whitelist, $blacklist); 139 | } 140 | $anArray[$prop->name] = $collect; 141 | 142 | // Otherwise, we can simply make it an array 143 | }else{ 144 | $anArray[$prop->name] = self::toArray($aValue, $nextDepth, $whitelist, $blacklist); 145 | } 146 | // Otherwise, we just use the base value 147 | }else{ 148 | 149 | $anArray[$prop->name] = $val; 150 | } 151 | } 152 | // All done, send it back! 153 | return $anArray; 154 | } 155 | } 156 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # NB: You are advised to use this project from here on in: http://laraveldoctrine.org/ 2 | 3 | # Doctrine2Bridge for Laravel 5 4 | 5 | Adds the power of Doctrine2 to Laraval 5 (including authentication and SQL query logging support). 6 | 7 | For Laravel4, see [opensolutions/doctrine2bridge](https://github.com/opensolutions/doctrine2bridge) 8 | 9 | Laravel's Eloquent ORM is nice for rapid development and the active model pattern. However there's little out 10 | there that can beat Doctrine2 when you need a more full-featured ORM. 11 | 12 | This is an integration of Doctrine 2.x to Laravel 5.x as a composer package. Doctrine's EntityManager instance is accessible through a facade named `D2EM` and the cache is directly available via `D2Cache`. 13 | 14 | Metadata is currently obtained via the [XML driver](http://docs.doctrine-project.org/en/latest/reference/xml-mapping.html). It should be easy to add additional drivers to this. 15 | 16 | Authentication support is also included via a `Auth/Doctrine2UserProvider` class. Documentation on integrating this with Laravel's own authentication system [can be found here](https://github.com/opensolutions/doctrine2bridge/wiki/Auth). 17 | 18 | ## Installation 19 | 20 | Installation is the usual for Laravel packages. You can find a detailed worked version of [how to install and test in the wiki](https://github.com/opensolutions/doctrine2bridge-l5/wiki/Install-from-Scratch). 21 | 22 | Insert the following in the packages (`require`) section of your composer.json file and run an update (`composer update`): 23 | 24 | "opensolutions/doctrine2bridge-l5": "2.4.*", 25 | 26 | Generally speaking, we'll try and match our minor versions (2.4.x) with Doctrine's but you should always use the latest `x` version of this. 27 | 28 | Add the service providers to your Laravel application in `app/config/app.php`. In the `'providers'` array add: 29 | 30 | 'Doctrine2Bridge\Doctrine2CacheBridgeServiceProvider', 31 | 'Doctrine2Bridge\Doctrine2BridgeServiceProvider', 32 | 33 | You'll need to publish and edit the configuration files: 34 | 35 | ./artisan vendor:publish --provider "Doctrine2Bridge\Doctrine2CacheBridgeServiceProvider" 36 | ./artisan vendor:publish --provider "Doctrine2Bridge\Doctrine2BridgeServiceProvider" 37 | 38 | This should get you a fresh copy of the configuration files (`d2bcache.php` and `db2doctrine.php`) in the configs directory. 39 | 40 | Now, edit these as well as setting Laravel5's own `cache.php` and `database.php` appropriately. 41 | 42 | The default directory for Doctrine2's xml schema is `database/xml`. This can be configured in `config/d2bdoctrine.php`. 43 | 44 | Documentation on integrating this with Laravel's own authentication system [can be found here](https://github.com/opensolutions/doctrine2bridge-l5/wiki/Auth). 45 | 46 | ## Usage 47 | 48 | Four bindings are created which can be injected via Laravel's IoC in the standard manner: 49 | 50 | * `Doctrine\ORM\EntityManagerInterface` (which is an instance of Doctrine\ORM\EntityManager) 51 | * `Doctrine\Common\Cache\Cache` (which is an instance of the appropriate cache provider) 52 | * `Doctrine\ORM\Mapping\ClassMetadataFactory` (used in this package by the console generator commands) 53 | * `Doctrine2Bridge\Support\Repository` (used by the `D2R` facade, see below) 54 | 55 | Three facades are provided - for the Doctrine2 cache, the entity manager and a convenience repository generator. These can be used as follows: 56 | 57 | D2Cache::save( $key, $value ); 58 | D2Cache::fetch( $key ); 59 | 60 | D2EM::persist( $object ); 61 | D2EM::flush(); 62 | $users = D2EM::getRepository( 'Entities\User' )->findAll(); 63 | 64 | Typically we'd create and use a repository as follows: 65 | 66 | $sample = D2EM::getRepository( '\Entities\SampleEntity' )->find(5); 67 | 68 | Assuming `d2bdoctrine.namespaces.models => 'Entities'`, then we can use the `D2R` facade in any of the following ways to achieve the same result: 69 | 70 | $sample = D2R::r( 'SampleEntity' )->find(5); 71 | $sample = D2R::r( 'Entities\SampleEntity' )->find(5); 72 | $sample = D2R::r( 'SampleEntity', 'Entities' )->find(5); 73 | 74 | ## More Detailed Usage 75 | 76 | The configuration file by default expects to find XML schema definitions under `database/xml`. Let's say for example we have a single schema file called `database/xml/Entities.SampleEntity.dcm.xml` containing: 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | Assuming you've configured your database connection parameters in the config file and you're positioned in the base directory of your project, we can create the entities, proxies and repositories with: 89 | 90 | ./artisan d2b:generate:entities 91 | ./artisan d2b:generate:proxies 92 | ./artisan d2b:generate:repositories 93 | 94 | There is also a handy shortcut for this: 95 | 96 | ./artisan d2b:generate:all 97 | 98 | Read the output of these commands as they may need to be run twice. 99 | 100 | We also bundle a full Doctrine2 CLI utilty so the above could also be done via: 101 | 102 | ./vendor/bin/d2b-doctrine2 orm:generate-entities database/ 103 | ./vendor/bin/d2b-doctrine2 orm:generate-proxies 104 | ./vendor/bin/d2b-doctrine2 orm:generate-repositories database/ 105 | 106 | You can also (drop) and create the database with: 107 | 108 | ./artisan d2b:schema:drop --commit 109 | ./artisan d2b:schema:create --commit 110 | 111 | And you can update and validate via: 112 | 113 | ./artisan d2b:schema:update --commit 114 | ./artisan d2b:schema:validate 115 | 116 | 117 | Now you can add some data to the database: 118 | 119 | $se = new Entities\SampleEntity; 120 | $se->setName( rand( 0, 100 ) ); 121 | D2EM::persist( $se ); 122 | D2EM::flush(); 123 | 124 | And query it: 125 | 126 | echo count( D2EM::getRepository( 'Entities\SampleEntity' )->findAll() ); 127 | 128 | I use the excellent [Skipper](http://www.skipper18.com/) to create and manage my XML schema files. 129 | 130 | ## Convenience Function for Repositories 131 | 132 | 133 | ## SQL Query Logging 134 | 135 | This package includes an implementation of `Doctrine\DBAL\Logging\SQLLlogger` which times the queries and calls the Laravel [Log](http://laravel.com/docs/errors#logging) facade to log the query execution times and the SQL queries. 136 | 137 | This logger can be enabled in the configuration file. 138 | 139 | ## License 140 | 141 | Like the Laravel framework itself, this project is open-sourced under the [MIT license](http://opensource.org/licenses/MIT). 142 | 143 | ## Inspiration 144 | 145 | Based on my original package [opensolutions/doctrine2bridge](https://github.com/opensolutions/doctrine2bridge) for Laravel4. Some additional inspiration when porting to Laravel5 from [mitchellvanw/laravel-doctrine](https://github.com/mitchellvanw/laravel-doctrine). 146 | 147 | -------------------------------------------------------------------------------- /src/Doctrine2Bridge/Doctrine2BridgeServiceProvider.php: -------------------------------------------------------------------------------- 1 | 22 | * @copyright Copyright (c) 2015 Open Source Solutions Limited 23 | * @license MIT 24 | */ 25 | class Doctrine2BridgeServiceProvider extends \Illuminate\Support\ServiceProvider 26 | { 27 | /** 28 | * Have we been configured? 29 | */ 30 | private $configured = true; 31 | 32 | /** 33 | * Bootstrap the application events. 34 | * 35 | * @return void 36 | */ 37 | public function boot( \Doctrine\Common\Cache\Cache $d2cache ) 38 | { 39 | // handle publishing of config file: 40 | $this->handleConfigs(); 41 | 42 | if( !$this->configured ) { 43 | if( isset( $_SERVER['argv'][1] ) && $_SERVER['argv'][1] != 'vendor:publish' ) 44 | echo "You must pubish the configuration files first: artisan vendor:publish\n"; 45 | return; 46 | } 47 | 48 | $d2em = $this->app->make( \Doctrine\ORM\EntityManagerInterface::class ); 49 | $d2em->getConfiguration()->setMetadataCacheImpl( $d2cache ); 50 | $d2em->getConfiguration()->setQueryCacheImpl( $d2cache ); 51 | $d2em->getConnection()->getConfiguration()->setResultCacheImpl( $d2cache ); 52 | 53 | if( Config::get( 'd2bdoctrine.sqllogger.enabled' ) ) 54 | $this->attachLogger( $d2em ); 55 | } 56 | 57 | 58 | 59 | /** 60 | * Register the service provider. 61 | * 62 | * @return void 63 | */ 64 | public function register() 65 | { 66 | if( !Config::get( 'd2bdoctrine' ) ) { 67 | if( isset( $_SERVER['argv'][1] ) && $_SERVER['argv'][1] != 'vendor:publish' ) 68 | echo "You must pubish the configuration files first: artisan vendor:publish\n"; 69 | $this->configured = false; 70 | return; 71 | } 72 | 73 | $this->registerEntityManager(); 74 | $this->registerClassMetadataFactory(); 75 | $this->registerConsoleCommands(); 76 | $this->registerRepositoryFacade(); 77 | $this->registerFacades(); 78 | 79 | if( Config::get( 'd2bdoctrine.auth.enabled' ) ) 80 | $this->setupAuth(); 81 | } 82 | 83 | /** 84 | * The Entity Manager - why we're all here! 85 | */ 86 | private function registerEntityManager() 87 | { 88 | $this->app->singleton( EntityManagerInterface::class, function( $app ) { 89 | 90 | $dconfig = new \Doctrine\ORM\Configuration; 91 | 92 | $driver = new \Doctrine\ORM\Mapping\Driver\XmlDriver( 93 | array( Config::get( 'd2bdoctrine.paths.xml_schema' ) ) 94 | ); 95 | 96 | $dconfig->setMetadataDriverImpl( $driver ); 97 | 98 | $dconfig->setProxyDir( Config::get( 'd2bdoctrine.paths.proxies' ) ); 99 | $dconfig->setProxyNamespace( Config::get( 'd2bdoctrine.namespaces.proxies' ) ); 100 | $dconfig->setAutoGenerateProxyClasses( Config::get( 'd2bdoctrine.autogen_proxies' ) ); 101 | 102 | $lconfig = $this->laravelToDoctrineConfigMapper(); 103 | 104 | //load prefix listener 105 | if( isset($lconfig['prefix']) && $lconfig['prefix'] && $lconfig['prefix'] !== '' ) { 106 | $tablePrefix = new TablePrefix( $lconfig['prefix']); 107 | $eventManager->addEventListener(Events::loadClassMetadata, $tablePrefix); 108 | } 109 | 110 | return EntityManager::create( $lconfig, $dconfig ); 111 | }); 112 | 113 | } 114 | 115 | /** 116 | * Register Facades to make developers' lives easier 117 | */ 118 | private function registerFacades() 119 | { 120 | // Shortcut so developers don't need to add an Alias in app/config/app.php 121 | \App::booting( function() { 122 | $loader = \Illuminate\Foundation\AliasLoader::getInstance(); 123 | $loader->alias( 'D2EM', 'Doctrine2Bridge\Support\Facades\Doctrine2' ); 124 | $loader->alias( 'D2R', 'Doctrine2Bridge\Support\Facades\Doctrine2Repository' ); 125 | }); 126 | } 127 | 128 | /** 129 | * Register Laravel console commands 130 | */ 131 | private function registerConsoleCommands() 132 | { 133 | $this->commands([ 134 | "\Doctrine2Bridge\Console\Generators\All", 135 | "\Doctrine2Bridge\Console\Generators\Entities", 136 | "\Doctrine2Bridge\Console\Generators\Proxies", 137 | "\Doctrine2Bridge\Console\Generators\Repositories", 138 | 139 | "\Doctrine2Bridge\Console\Schema\Create", 140 | "\Doctrine2Bridge\Console\Schema\Drop", 141 | "\Doctrine2Bridge\Console\Schema\Update", 142 | "\Doctrine2Bridge\Console\Schema\Validate", 143 | ]); 144 | } 145 | 146 | /** 147 | * Metadata Factory - mainly used by schema console commands 148 | */ 149 | private function registerClassMetadataFactory() 150 | { 151 | $this->app->singleton( ClassMetadataFactory::class, function( $app ) { 152 | return $app[EntityManagerInterface::class]->getMetadataFactory(); 153 | }); 154 | } 155 | 156 | 157 | private function registerRepositoryFacade() 158 | { 159 | $this->app->bind( D2Repository::class, function( $app ) { 160 | return new D2Repository; 161 | }); 162 | 163 | \App::booting( function() { 164 | $loader = \Illuminate\Foundation\AliasLoader::getInstance(); 165 | $loader->alias( 'D2R', 'Doctrine2Bridge\Support\Facades\Doctrine2Repository' ); 166 | }); 167 | 168 | } 169 | 170 | /** 171 | * Attach Laravel logging to Doctrine for debugging / profiling 172 | */ 173 | private function attachLogger( $d2em ) 174 | { 175 | $logger = new Logger\Laravel; 176 | if( Config::has( 'd2bdoctrine.sqllogger.level' ) ) 177 | $logger->setLevel( Config::get( 'd2bdoctrine.sqllogger.level' ) ); 178 | 179 | $d2em->getConnection()->getConfiguration()->setSQLLogger( $logger ); 180 | } 181 | 182 | /** 183 | * Set up Laravel authentication via Doctrine2 provider 184 | */ 185 | private function setupAuth() 186 | { 187 | Auth::extend( 'doctrine2bridge', function() { 188 | return new \Illuminate\Auth\Guard( 189 | new \Doctrine2Bridge\Auth\Doctrine2UserProvider( 190 | \D2EM::getRepository( Config::get( 'd2bdoctrine.auth.entity' ) ), 191 | new \Illuminate\Hashing\BcryptHasher 192 | ), 193 | \App::make('session.store') 194 | ); 195 | }); 196 | } 197 | 198 | 199 | /** 200 | * Publish configuration file 201 | */ 202 | private function handleConfigs() { 203 | $configPath = __DIR__ . '/../config/d2bdoctrine.php'; 204 | $this->publishes( [ $configPath => config_path('d2bdoctrine.php') ] ); 205 | $this->mergeConfigFrom( $configPath, 'd2bdoctrine' ); 206 | } 207 | 208 | 209 | /** 210 | * Convert Laravel5's database configuration to something what Doctrine2's 211 | * DBAL providers can use. 212 | * 213 | * @return array 214 | */ 215 | private function laravelToDoctrineConfigMapper() 216 | { 217 | switch( Config::get( 'database.default' ) ) { 218 | case 'mysql': 219 | return [ 220 | 'driver' => 'pdo_mysql', 221 | 'dbname' => Config::get( 'database.connections.mysql.database' ), 222 | 'user' => Config::get( 'database.connections.mysql.username' ), 223 | 'password' => Config::get( 'database.connections.mysql.password' ), 224 | 'host' => Config::get( 'database.connections.mysql.host' ), 225 | 'charset' => Config::get( 'database.connections.mysql.charset' ), 226 | 'prefix' => Config::get( 'database.connections.mysql.prefix' ), 227 | ]; 228 | break; 229 | 230 | case 'pgsql': 231 | return [ 232 | 'driver' => 'pdo_pgsql', 233 | 'dbname' => Config::get( 'database.connections.pgsql.database' ), 234 | 'user' => Config::get( 'database.connections.pgsql.username' ), 235 | 'password' => Config::get( 'database.connections.pgsql.password' ), 236 | 'host' => Config::get( 'database.connections.pgsql.host' ), 237 | 'charset' => Config::get( 'database.connections.pgsql.charset' ), 238 | 'prefix' => Config::get( 'database.connections.pgsql.prefix' ), 239 | ]; 240 | break; 241 | 242 | case 'sqlite': 243 | return [ 244 | 'driver' => 'pdo_sqlite', 245 | 'path' => Config::get( 'database.connections.sqlite.database' ), 246 | 'user' => Config::get( 'database.connections.sqlite.username' ), 247 | 'password' => Config::get( 'database.connections.sqlite.password' ), 248 | 'prefix' => Config::get( 'database.connections.sqlite.prefix' ), 249 | ]; 250 | break; 251 | 252 | default: 253 | throw new Doctrine2Bridge\Exception\ImplementationNotFound( Config::get( 'database.default' ) ); 254 | } 255 | } 256 | } 257 | --------------------------------------------------------------------------------