├── .gitignore ├── .travis.yml ├── LICENSE ├── README.md ├── composer.json ├── config └── doctrine.php ├── phpunit.xml ├── src ├── Cache │ ├── ApcProvider.php │ ├── MemcacheProvider.php │ ├── NullProvider.php │ ├── Provider.php │ ├── RedisProvider.php │ └── XcacheProvider.php ├── CacheManager.php ├── Configuration │ ├── DriverMapper.php │ ├── LaravelNamingStrategy.php │ ├── Mapper.php │ ├── OCIMapper.php │ ├── SqlMapper.php │ └── SqliteMapper.php ├── Console │ ├── DqlCommand.php │ ├── GenerateProxiesCommand.php │ ├── SchemaCreateCommand.php │ ├── SchemaDropCommand.php │ └── SchemaUpdateCommand.php ├── DoctrineUserProvider.php ├── EntityManagerFacade.php ├── EventListeners │ ├── SoftDeletableListener.php │ └── TablePrefix.php ├── Filters │ └── TrashedFilter.php ├── LaravelDoctrineServiceProvider.php ├── Traits │ ├── Authentication.php │ ├── RememberToken.php │ ├── SoftDeletes.php │ └── Timestamps.php └── Validation │ └── DoctrinePresenceVerifier.php └── tests ├── Configuration ├── DriverMapperTest.php ├── LaravelNamingStrategyTest.php ├── OCIMapperTest.php ├── SqlMapperTest.php └── SqliteMapperTest.php ├── EventListener └── TablePrefixTest.php └── Stubs └── ApplicationStub.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor 2 | /.idea 3 | composer.phar 4 | composer.lock 5 | .DS_Store 6 | .idea/* 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3 5 | - 5.4 6 | - 5.5 7 | - 5.6 8 | - hhvm 9 | 10 | before_script: 11 | - composer self-update 12 | - composer install --prefer-source --no-interaction --dev 13 | 14 | script: phpunit 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 - Mitchell van Wijngaarden 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | 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, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Doctrine 2 for Laravel (NO LONGER MAINTAINED! Try [laravel-doctrine/orm](https://github.com/laravel-doctrine/orm) instead!) 2 | 3 | [![Latest Stable Version](https://poser.pugx.org/mitchellvanw/laravel-doctrine/version.png)](https://packagist.org/packages/mitchellvanw/laravel-doctrine) 4 | [![License](https://poser.pugx.org/mitchellvanw/laravel-doctrine/license.png)](https://packagist.org/packages/mitchellvanw/laravel-doctrine) 5 | [![Total Downloads](https://poser.pugx.org/mitchellvanw/laravel-doctrine/downloads.png)](https://packagist.org/packages/mitchellvanw/laravel-doctrine) 6 | 7 | A Doctrine 2 implementation that melts with Laravel 4. 8 | 9 | ## Documentation 10 | 11 | Begin reading [the full documentation](https://github.com/mitchellvanw/laravel-doctrine/wiki) here or go to a specific chapter right away. 12 | 13 | 1. [Installation](https://github.com/mitchellvanw/laravel-doctrine/wiki/Installation) 14 | 2. [How It Works](https://github.com/mitchellvanw/laravel-doctrine/wiki/How-It-Works) 15 | 1. [Basics](https://github.com/mitchellvanw/laravel-doctrine/wiki/Basics) 16 | 2. [Entity Manager](https://github.com/mitchellvanw/laravel-doctrine/wiki/Entity-Manager) 17 | 3. [Timestamps](https://github.com/mitchellvanw/laravel-doctrine/wiki/Timestamps) 18 | 4. [Soft Deleting](https://github.com/mitchellvanw/laravel-doctrine/wiki/Soft-Deleting) 19 | 5. [Authentication](https://github.com/mitchellvanw/laravel-doctrine/wiki/Authentication) 20 | 3. [Schemas](https://github.com/mitchellvanw/laravel-doctrine/wiki/Schemas) 21 | 4. [Doctrine Configuration](https://github.com/mitchellvanw/laravel-doctrine/wiki/Doctrine-Configuration) 22 | 1. [Metadata Configuration](https://github.com/mitchellvanw/laravel-doctrine/wiki/Metadata-Configuration) 23 | 2. [Annotation Reader](https://github.com/mitchellvanw/laravel-doctrine/wiki/Annotation-Reader) 24 | 3. [Metadata](https://github.com/mitchellvanw/laravel-doctrine/wiki/Metadata) 25 | 5. [MIT License](https://github.com/mitchellvanw/laravel-doctrine/blob/master/LICENSE) 26 | 27 | ## Caveats 28 | 29 | At the moment Doctrine\migrations version 1.0 is still in alpha. As a result the composer install may require you to change 30 | the `minimum-stability` in your `composer.json` to `dev`. 31 | 32 | If you don't want to affect the stability of the rest of the packages, you can add the following property in your `composer.json`: 33 | 34 | "prefer-stable": true 35 | 36 | ## Installation 37 | 38 | Begin by installing the package through Composer. Edit your project's `composer.json` to require `mitchellvanw/laravel-doctrine`. 39 | 40 | > This package is still in it's early stages, but fully functional. Is it possible that the API might change slightly, no drastic changes. 41 | 42 | ```php 43 | "require": { 44 | "mitchellvanw/laravel-doctrine": "0.5.*" 45 | } 46 | ``` 47 | 48 | Next use Composer to update your project from the the Terminal: 49 | 50 | ```php 51 | php composer.phar update 52 | ``` 53 | 54 | Once the package has been installed you'll need to add the service provider. Open your `app/config/app.php` configuration file, and add a new item to the `providers` array. 55 | 56 | ```php 57 | 'Mitch\LaravelDoctrine\LaravelDoctrineServiceProvider' 58 | ``` 59 | 60 | After This you'll need to add the facade. Open your `app/config/app.php` configuration file, and add a new item to the `aliases` array. 61 | 62 | ```php 63 | 'EntityManager' => 'Mitch\LaravelDoctrine\EntityManagerFacade' 64 | ``` 65 | 66 | It's recommended to publish the package configuration. 67 | 68 | ```php 69 | php artisan config:publish mitchellvanw/laravel-doctrine --path=vendor/mitchellvanw/laravel-doctrine/config 70 | ``` 71 | 72 | ## 2 Minutes 73 | 74 | This package uses the Laravel database configuration and thus it works right out of the box. With the [Entity Manager](https://github.com/mitchellvanw/laravel-doctrine/wiki/Entity-Manager) facade (or service locator) you can interact with repositories. 75 | It might be wise to [check out the Doctrine 2 docs](http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/index.html) to know how it works. 76 | The little example below shows how to use the EntityManager in it simplest form. 77 | 78 | ```php 79 | setName('Mitchell'); 83 | 84 | EntityManager::persist($user); 85 | EntityManager::flush(); 86 | ``` 87 | 88 | The `User` used in the example above looks like this. 89 | 90 | ```php 91 | id; 116 | } 117 | 118 | public function getName() 119 | { 120 | return $this->name; 121 | } 122 | 123 | public function setName($name) 124 | { 125 | $this->name = $name; 126 | } 127 | } 128 | ``` 129 | 130 | If you've only used Eloquent and its models this might look bloated or frightening, but it's actually very simple. Let me break the class down. 131 | 132 | ```php 133 | =5.5.0", 15 | "illuminate/support": "4.*|5.*", 16 | "doctrine/orm": "2.5.*", 17 | "doctrine/migrations": "1.*" 18 | }, 19 | "require-dev": { 20 | "mockery/mockery": "dev-master", 21 | "phpunit/phpunit": "3.7.*" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "Mitch\\LaravelDoctrine\\": "src/", 26 | "Tests\\": "tests/" 27 | } 28 | }, 29 | "minimum-stability": "dev", 30 | "prefer-stable": true 31 | } 32 | -------------------------------------------------------------------------------- /config/doctrine.php: -------------------------------------------------------------------------------- 1 | false, 5 | 6 | 'metadata' => [ 7 | base_path('app/models') 8 | ], 9 | 10 | 'proxy' => [ 11 | 'auto_generate' => false, 12 | 'directory' => null, 13 | 'namespace' => null 14 | ], 15 | 16 | // Available: null, apc, xcache, redis, memcache 17 | 'cache_provider' => null, 18 | 19 | 'cache' => [ 20 | 'redis' => [ 21 | 'host' => '127.0.0.1', 22 | 'port' => 6379, 23 | 'database' => 1 24 | ], 25 | 'memcache' => [ 26 | 'host' => '127.0.0.1', 27 | 'port' => 11211 28 | ] 29 | ], 30 | 31 | 'repository' => 'Doctrine\ORM\EntityRepository', 32 | 33 | 'repositoryFactory' => null, 34 | 35 | 'logger' => null 36 | ]; 37 | -------------------------------------------------------------------------------- /phpunit.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 15 | ./tests/ 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /src/Cache/ApcProvider.php: -------------------------------------------------------------------------------- 1 | connect($config['host'], $config['port']); 15 | 16 | $cache = new MemcacheCache; 17 | $cache->setMemcache($memcache); 18 | return $cache; 19 | } 20 | 21 | public function isAppropriate($provider) 22 | { 23 | return $provider == 'memcache'; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/Cache/NullProvider.php: -------------------------------------------------------------------------------- 1 | connect($config['host'], $config['port']); 15 | if (isset($config['database'])) 16 | $redis->select($config['database']); 17 | 18 | $cache = new RedisCache; 19 | $cache->setRedis($redis); 20 | return $cache; 21 | } 22 | 23 | public function isAppropriate($provider) 24 | { 25 | return $provider == 'redis'; 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Cache/XcacheProvider.php: -------------------------------------------------------------------------------- 1 | config = $config; 12 | } 13 | 14 | public function getCache($type) 15 | { 16 | foreach ($this->providers as $provider) 17 | if ($provider->isAppropriate($type)) 18 | return $provider->make($this->getConfig($type)); 19 | 20 | return null; 21 | } 22 | 23 | private function getConfig($provider) 24 | { 25 | return isset($this->config[$provider]) ? $this->config[$provider] : null; 26 | } 27 | 28 | public function add(Provider $provider) 29 | { 30 | $this->providers[] = $provider; 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Configuration/DriverMapper.php: -------------------------------------------------------------------------------- 1 | mappers[] = $mapper; 23 | } 24 | 25 | /** 26 | * Map the Laravel configuration to a configuration driver, return the result. 27 | * 28 | * @param $configuration 29 | * @return array 30 | * @throws Exception 31 | */ 32 | public function map($configuration) 33 | { 34 | foreach ($this->mappers as $mapper) 35 | if ($mapper->isAppropriateFor($configuration)) 36 | return $mapper->map($configuration); 37 | 38 | throw new Exception("Driver {$configuration['driver']} unsupported by package at this time."); 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /src/Configuration/LaravelNamingStrategy.php: -------------------------------------------------------------------------------- 1 | str = $str; 16 | } 17 | 18 | /** 19 | * Returns a table name for an entity class. 20 | * 21 | * @param string $className The fully-qualified class name. 22 | * 23 | * @return string A table name. 24 | */ 25 | public function classToTableName($className) 26 | { 27 | return $this->str->plural($this->classToFieldName($className)); 28 | } 29 | 30 | /** 31 | * Returns a column name for a property. 32 | * 33 | * @param string $propertyName A property name. 34 | * @param string|null $className The fully-qualified class name. 35 | * 36 | * @return string A column name. 37 | */ 38 | public function propertyToColumnName($propertyName, $className = null) 39 | { 40 | return $this->str->snake($propertyName); 41 | } 42 | 43 | /** 44 | * Returns the default reference column name. 45 | * 46 | * @return string A column name. 47 | */ 48 | public function referenceColumnName() 49 | { 50 | return 'id'; 51 | } 52 | 53 | /** 54 | * Returns a join column name for a property. 55 | * 56 | * @param string $propertyName A property name. 57 | * 58 | * @return string A join column name. 59 | */ 60 | public function joinColumnName($propertyName) 61 | { 62 | return $this->str->snake($this->str->singular($propertyName)) . '_' . $this->referenceColumnName(); 63 | } 64 | 65 | /** 66 | * Returns a join table name. 67 | * 68 | * @param string $sourceEntity The source entity. 69 | * @param string $targetEntity The target entity. 70 | * @param string|null $propertyName A property name. 71 | * 72 | * @return string A join table name. 73 | */ 74 | public function joinTableName($sourceEntity, $targetEntity, $propertyName = null) 75 | { 76 | $names = [ 77 | $this->classToFieldName($sourceEntity), 78 | $this->classToFieldName($targetEntity) 79 | ]; 80 | 81 | sort($names); 82 | 83 | return implode('_', $names); 84 | } 85 | 86 | /** 87 | * Returns the foreign key column name for the given parameters. 88 | * 89 | * @param string $entityName An entity. 90 | * @param string|null $referencedColumnName A property. 91 | * 92 | * @return string A join column name. 93 | */ 94 | public function joinKeyColumnName($entityName, $referencedColumnName = null) 95 | { 96 | return $this->classToFieldName($entityName) . '_' . 97 | ($referencedColumnName ?: $this->referenceColumnName()); 98 | } 99 | 100 | private function classToFieldName($className) 101 | { 102 | return $this->str->snake(class_basename($className)); 103 | } 104 | 105 | /** 106 | * Returns a column name for an embedded property. 107 | * 108 | * @param string $propertyName 109 | * @param string $embeddedColumnName 110 | * 111 | * @return string 112 | */ 113 | public function embeddedFieldToColumnName($propertyName, $embeddedColumnName, $className = null, $embeddedClassName = null) 114 | { 115 | return $propertyName.'_'.$embeddedColumnName; 116 | } 117 | } 118 | -------------------------------------------------------------------------------- /src/Configuration/Mapper.php: -------------------------------------------------------------------------------- 1 | false]; 15 | $optional = ['servicename', 'instancename']; 16 | 17 | foreach ($optional as $opt) { 18 | if(isset($configuration[$opt])) 19 | $defaults[$opt] = $configuration[$opt]; 20 | } 21 | 22 | return array_merge($defaults, [ 23 | 'driver' => $this->driver($configuration['driver']), 24 | 'port' => @$configuration['port'] ? $configuration['port'] : 1521, 25 | 'host' => $configuration['host'], 26 | 'dbname' => $configuration['database'], 27 | 'user' => $configuration['username'], 28 | 'password' => $configuration['password'], 29 | 'charset' => $configuration['charset'], 30 | 'prefix' => @$configuration['prefix'] ? $configuration['prefix'] : null 31 | ]); 32 | } 33 | 34 | /** 35 | * Is suitable for mapping configurations that use an oracle setup. 36 | * 37 | * @param array $configuration 38 | * @return boolean 39 | */ 40 | public function isAppropriateFor(array $configuration) 41 | { 42 | return in_array($configuration['driver'], ['oci8', 'pdo_oci', 'oracle']); 43 | } 44 | 45 | /** 46 | * Maps the Laravel driver syntax to an Sql doctrine format. 47 | * oci8 and pdo_oci are available to but oracle will use oci8 48 | * 49 | * @param $l4Driver 50 | * @return string 51 | */ 52 | public function driver($l4Driver) 53 | { 54 | $doctrineDrivers = ['oci8' => 'oci8', 'pdo_oci' => 'pdo_oci', 'oracle' => 'oci8']; 55 | 56 | return $doctrineDrivers[$l4Driver]; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/Configuration/SqlMapper.php: -------------------------------------------------------------------------------- 1 | $this->driver($configuration['driver']), 15 | 'host' => $configuration['host'], 16 | 'dbname' => $configuration['database'], 17 | 'user' => $configuration['username'], 18 | 'password' => $configuration['password'], 19 | 'charset' => $configuration['charset'], 20 | 'prefix' => @$configuration['prefix'] ? $configuration['prefix'] : null 21 | ]; 22 | } 23 | 24 | /** 25 | * Is suitable for mapping configurations that use a mysql, postgres or sqlserv setup. 26 | * 27 | * @param array $configuration 28 | * @return boolean 29 | */ 30 | public function isAppropriateFor(array $configuration) 31 | { 32 | return in_array($configuration['driver'], ['sqlsrv', 'mysql', 'pgsql']); 33 | } 34 | 35 | /** 36 | * Maps the Laravel driver syntax to an Sql doctrine format. 37 | * 38 | * @param $l4Driver 39 | * @return string 40 | */ 41 | public function driver($l4Driver) 42 | { 43 | $doctrineDrivers = ['mysql' => 'pdo_mysql', 'sqlsrv' => 'pdo_sqlsrv', 'pgsql' => 'pdo_pgsql']; 44 | 45 | return $doctrineDrivers[$l4Driver]; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Configuration/SqliteMapper.php: -------------------------------------------------------------------------------- 1 | 'pdo_sqlite', 15 | 'user' => @$configuration['username'], 16 | 'password' => @$configuration['password'], 17 | 'prefix' => @$configuration['prefix'] ? $configuration['prefix'] : null 18 | ]; 19 | $this->databaseLocation($configuration, $sqliteConfig); 20 | return $sqliteConfig; 21 | } 22 | 23 | /** 24 | * Is only suitable for sqlite configuration mapping. 25 | * 26 | * @param array $configuration 27 | * @return bool 28 | */ 29 | public function isAppropriateFor(array $configuration) 30 | { 31 | return $configuration['driver'] == 'sqlite'; 32 | } 33 | 34 | /** 35 | * Determines the location of the database and appends this to the sqlite configuration. 36 | * 37 | * @param $configuration 38 | * @param $sqliteConfig 39 | */ 40 | private function databaseLocation($configuration, &$sqliteConfig) 41 | { 42 | if ($configuration['database'] == ':memory:') 43 | $sqliteConfig['memory'] = true; 44 | else 45 | $sqliteConfig['path'] = $configuration['database']; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/Console/DqlCommand.php: -------------------------------------------------------------------------------- 1 | entityManager = $entityManager; 36 | } 37 | 38 | public function fire() 39 | { 40 | 41 | } 42 | 43 | protected function getArguments() 44 | { 45 | return [ 46 | ['dql', null, InputArgument::REQUIRED, 'DQL query.'] 47 | ]; 48 | } 49 | 50 | protected function getOptions() 51 | { 52 | return [ 53 | ['hydrate', null, InputOption::VALUE_OPTIONAL, 'Hydrate type. Available: object, array, scalar, single_scalar, simpleobject'] 54 | ]; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Console/GenerateProxiesCommand.php: -------------------------------------------------------------------------------- 1 | entityManager = $entityManager; 34 | } 35 | 36 | public function fire() 37 | { 38 | $this->info('Starting proxy generation....'); 39 | $metadata = $this->entityManager->getMetadataFactory()->getAllMetadata(); 40 | if (empty($metadata)) { 41 | $this->error('No metadata found to generate any entities.'); 42 | exit; 43 | } 44 | $directory = $this->laravel['config']['doctrine::doctrine.proxy.directory']; 45 | if ( ! $directory) { 46 | $this->error('The proxy directory has not been set.'); 47 | exit; 48 | } 49 | $this->info('Processing entities:'); 50 | foreach ($metadata as $item) { 51 | $this->line($item->name); 52 | } 53 | $this->entityManager->getProxyFactory()->generateProxyClasses($metadata, $directory); 54 | $this->info('Proxies have been created.'); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Console/SchemaCreateCommand.php: -------------------------------------------------------------------------------- 1 | tool = $tool; 43 | $this->metadata = $metadata; 44 | } 45 | 46 | /** 47 | * Execute the console command. 48 | * 49 | * @return void 50 | */ 51 | public function fire() 52 | { 53 | if ($this->option('sql')) { 54 | $this->info('Outputting create query:'.PHP_EOL); 55 | $sql = $this->tool->getCreateSchemaSql($this->metadata->getAllMetadata()); 56 | $this->info(implode(';'.PHP_EOL, $sql)); 57 | } else { 58 | $this->info('Creating database schema...'); 59 | $this->tool->createSchema($this->metadata->getAllMetadata()); 60 | $this->info('Schema has been created!'); 61 | } 62 | } 63 | 64 | protected function getOptions() 65 | { 66 | return [ 67 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute creation.'] 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/Console/SchemaDropCommand.php: -------------------------------------------------------------------------------- 1 | tool = $tool; 43 | $this->metadata = $metadata; 44 | } 45 | 46 | /** 47 | * Execute the console command. 48 | * 49 | * @return void 50 | */ 51 | public function fire() 52 | { 53 | $sql = $this->tool->getDropSchemaSQL($this->metadata->getAllMetadata()); 54 | if (empty($sql)) { 55 | $this->info('Current models do not exist in schema.'); 56 | return; 57 | } 58 | if ($this->option('sql')) { 59 | $this->info('Outputting drop query:'); 60 | $this->info(implode(';' . PHP_EOL, $sql)); 61 | } else { 62 | $this->info('Dropping database schema....'); 63 | $this->tool->dropSchema($this->metadata->getAllMetadata()); 64 | $this->info('Schema has been dropped!'); 65 | } 66 | } 67 | 68 | protected function getOptions() 69 | { 70 | return [ 71 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute drop.'], 72 | ]; 73 | } 74 | } 75 | 76 | -------------------------------------------------------------------------------- /src/Console/SchemaUpdateCommand.php: -------------------------------------------------------------------------------- 1 | tool = $tool; 43 | $this->metadata = $metadata; 44 | } 45 | 46 | /** 47 | * Execute the console command. 48 | * 49 | * @return void 50 | */ 51 | public function fire() 52 | { 53 | $this->info('Checking if database needs updating....'); 54 | $clean = $this->option('clean'); 55 | $sql = $this->tool->getUpdateSchemaSql($this->metadata->getAllMetadata(), $clean); 56 | if (empty($sql)) { 57 | $this->info('No updates found.'); 58 | return; 59 | } 60 | if ($this->option('sql')) { 61 | $this->info('Outputting update query:'); 62 | $this->info(implode(';' . PHP_EOL, $sql)); 63 | } else { 64 | $this->info('Updating database schema....'); 65 | $this->tool->updateSchema($this->metadata->getAllMetadata()); 66 | $this->info('Schema has been updated!'); 67 | } 68 | } 69 | 70 | protected function getOptions() 71 | { 72 | return [ 73 | ['sql', false, InputOption::VALUE_NONE, 'Dumps SQL query and does not execute update.'], 74 | ['clean', null, InputOption::VALUE_OPTIONAL, 'When using clean model all non-relevant to this metadata assets will be cleared.'] 75 | ]; 76 | } 77 | } 78 | 79 | -------------------------------------------------------------------------------- /src/DoctrineUserProvider.php: -------------------------------------------------------------------------------- 1 | hasher = $hasher; 32 | $this->entityManager = $entityManager; 33 | $this->entity = $entity; 34 | } 35 | /** 36 | * Retrieve a user by their unique identifier. 37 | 38 | * @param mixed $identifier 39 | * @return UserInterface|null 40 | */ 41 | public function retrieveById($identifier) 42 | { 43 | return $this->getRepository()->find($identifier); 44 | } 45 | 46 | /** 47 | * Retrieve a user by by their unique identifier and "remember me" token. 48 | 49 | * @param mixed $identifier 50 | * @param string $token 51 | * @return UserInterface|null 52 | */ 53 | public function retrieveByToken($identifier, $token) 54 | { 55 | $entity = $this->getEntity(); 56 | return $this->getRepository()->findOneBy([ 57 | $entity->getKeyName() => $identifier, 58 | $entity->getRememberTokenName() => $token 59 | ]); 60 | } 61 | 62 | /** 63 | * Update the "remember me" token for the given user in storage. 64 | 65 | * @param UserInterface $user 66 | * @param string $token 67 | * @return void 68 | */ 69 | public function updateRememberToken(UserInterface $user, $token) 70 | { 71 | $user->setRememberToken($token); 72 | $this->entityManager->persist($user); 73 | $this->entityManager->flush(); 74 | } 75 | 76 | /** 77 | * Retrieve a user by the given credentials. 78 | 79 | * @param array $credentials 80 | * @return UserInterface|null 81 | */ 82 | public function retrieveByCredentials(array $credentials) 83 | { 84 | $criteria = []; 85 | foreach ($credentials as $key => $value) 86 | if ( ! str_contains($key, 'password')) 87 | $criteria[$key] = $value; 88 | 89 | return $this->getRepository()->findOneBy($criteria); 90 | } 91 | 92 | /** 93 | * Validate a user against the given credentials. 94 | 95 | * @param UserInterface $user 96 | * @param array $credentials 97 | * @return bool 98 | */ 99 | public function validateCredentials(UserInterface $user, array $credentials) 100 | { 101 | return $this->hasher->check($credentials['password'], $user->getAuthPassword()); 102 | } 103 | 104 | /** 105 | * Returns repository for the entity. 106 | * 107 | * @return EntityRepository 108 | */ 109 | private function getRepository() 110 | { 111 | return $this->entityManager->getRepository($this->entity); 112 | } 113 | 114 | /** 115 | * Returns instantiated entity. 116 | * 117 | * @return mixed 118 | */ 119 | private function getEntity() 120 | { 121 | return new $this->entity; 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /src/EntityManagerFacade.php: -------------------------------------------------------------------------------- 1 | getEntityManager(); 11 | $unitOfWork = $entityManager->getUnitOfWork(); 12 | foreach ($unitOfWork->getScheduledEntityDeletions() as $entity) { 13 | if ($this->isSoftDeletable($entity)) { 14 | $metadata = $entityManager->getClassMetadata(get_class($entity)); 15 | $oldDeletedAt = $metadata->getFieldValue($entity, 'deletedAt'); 16 | if ($oldDeletedAt instanceof DateTime) { 17 | continue; 18 | } 19 | $now = new DateTime; 20 | $metadata->setFieldValue($entity, 'deletedAt', $now); 21 | $entityManager->persist($entity); 22 | 23 | $unitOfWork->propertyChanged($entity, 'deletedAt', $oldDeletedAt, $now); 24 | $unitOfWork->scheduleExtraUpdate($entity, [ 25 | 'deletedAt' => [$oldDeletedAt, $now] 26 | ]); 27 | } 28 | } 29 | } 30 | 31 | private function isSoftDeletable($entity) 32 | { 33 | return array_key_exists('Mitch\LaravelDoctrine\Traits\SoftDeletes', class_uses($entity)); 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/EventListeners/TablePrefix.php: -------------------------------------------------------------------------------- 1 | prefix = (string) $prefix; 17 | } 18 | 19 | /** 20 | * loadClassMetadata 21 | * 22 | * @link http://doctrine-orm.readthedocs.org/en/latest/cookbook/sql-table-prefixes.html 23 | * @param LoadClassMetadataEventArgs $eventArgs 24 | */ 25 | public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs) 26 | { 27 | $classMetadata = $eventArgs->getClassMetadata(); 28 | $classMetadata->setTableName($this->prefix . $classMetadata->getTableName()); 29 | 30 | //if we use sequences, also prefix the sequence name 31 | if($classMetadata->isIdGeneratorSequence()) { 32 | 33 | $sequenceDefinition = $classMetadata->sequenceGeneratorDefinition; 34 | $sequenceDefinition['sequenceName'] = $this->prefix . $sequenceDefinition['sequenceName']; 35 | 36 | $classMetadata->setSequenceGeneratorDefinition($sequenceDefinition); 37 | } 38 | 39 | foreach ($classMetadata->getAssociationMappings() as $fieldName => $mapping) { 40 | if ($mapping['type'] == \Doctrine\ORM\Mapping\ClassMetadataInfo::MANY_TO_MANY) { 41 | $mappedTableName = $classMetadata->associationMappings[$fieldName]['joinTable']['name']; 42 | $classMetadata->associationMappings[$fieldName]['joinTable']['name'] = $this->prefix . $mappedTableName; 43 | } 44 | } 45 | } 46 | 47 | } 48 | 49 | -------------------------------------------------------------------------------- /src/Filters/TrashedFilter.php: -------------------------------------------------------------------------------- 1 | isSoftDeletable($metadata->rootEntityName) ? "{$table}.deleted_at IS NULL OR CURRENT_TIMESTAMP < {$table}.deleted_at" : ''; 11 | } 12 | 13 | private function isSoftDeletable($entity) 14 | { 15 | return array_key_exists('Mitch\LaravelDoctrine\Traits\SoftDeletes', class_uses($entity)); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /src/LaravelDoctrineServiceProvider.php: -------------------------------------------------------------------------------- 1 | package('mitchellvanw/laravel-doctrine', 'doctrine', __DIR__ . '/..'); 34 | $this->extendAuthManager(); 35 | } 36 | 37 | /** 38 | * Register the service provider. 39 | * @return void 40 | */ 41 | public function register() 42 | { 43 | $this->registerConfigurationMapper(); 44 | $this->registerCacheManager(); 45 | $this->registerEntityManager(); 46 | $this->registerClassMetadataFactory(); 47 | $this->registerValidationVerifier(); 48 | 49 | $this->commands([ 50 | 'Mitch\LaravelDoctrine\Console\GenerateProxiesCommand', 51 | 'Mitch\LaravelDoctrine\Console\SchemaCreateCommand', 52 | 'Mitch\LaravelDoctrine\Console\SchemaUpdateCommand', 53 | 'Mitch\LaravelDoctrine\Console\SchemaDropCommand' 54 | ]); 55 | } 56 | 57 | /** 58 | * The driver mapper's instance needs to be accessible from anywhere in the application, 59 | * for registering new mapping configurations or other storage libraries. 60 | */ 61 | private function registerConfigurationMapper() 62 | { 63 | $this->app->bind(DriverMapper::class, function () { 64 | $mapper = new DriverMapper; 65 | $mapper->registerMapper(new SqlMapper); 66 | $mapper->registerMapper(new SqliteMapper); 67 | $mapper->registerMapper(new OCIMapper); 68 | return $mapper; 69 | }); 70 | } 71 | 72 | /** 73 | * Registers a new presence verifier for Laravel 4 validation. Specifically, this 74 | * is for the use of the Doctrine ORM. 75 | */ 76 | public function registerValidationVerifier() 77 | { 78 | $this->app->bindShared('validation.presence', function() 79 | { 80 | return new DoctrinePresenceVerifier(EntityManagerInterface::class); 81 | }); 82 | } 83 | 84 | public function registerCacheManager() 85 | { 86 | $this->app->bind(CacheManager::class, function ($app) { 87 | $manager = new CacheManager($app['config']['doctrine::doctrine.cache']); 88 | $manager->add(new Cache\ApcProvider); 89 | $manager->add(new Cache\MemcacheProvider); 90 | $manager->add(new Cache\RedisProvider); 91 | $manager->add(new Cache\XcacheProvider); 92 | $manager->add(new Cache\NullProvider); 93 | return $manager; 94 | }); 95 | } 96 | 97 | private function registerEntityManager() 98 | { 99 | $this->app->singleton(EntityManager::class, function ($app) { 100 | $config = $app['config']['doctrine::doctrine']; 101 | $metadata = Setup::createAnnotationMetadataConfiguration( 102 | $config['metadata'], 103 | $app['config']['app.debug'], 104 | $config['proxy']['directory'], 105 | $app[CacheManager::class]->getCache($config['cache_provider']), 106 | $config['simple_annotations'] 107 | ); 108 | $metadata->addFilter('trashed', TrashedFilter::class); 109 | $metadata->setAutoGenerateProxyClasses($config['proxy']['auto_generate']); 110 | $metadata->setDefaultRepositoryClassName($config['repository']); 111 | $metadata->setSQLLogger($config['logger']); 112 | $metadata->setNamingStrategy($app->make(LaravelNamingStrategy::class)); 113 | 114 | if (isset($config['proxy']['namespace'])) 115 | $metadata->setProxyNamespace($config['proxy']['namespace']); 116 | 117 | $eventManager = new EventManager; 118 | 119 | $connection_config = $this->mapLaravelToDoctrineConfig($app['config']); 120 | 121 | //load prefix listener 122 | if(isset($connection_config['prefix'])) { 123 | $tablePrefix = new TablePrefix($connection_config['prefix']); 124 | $eventManager->addEventListener(Events::loadClassMetadata, $tablePrefix); 125 | } 126 | 127 | $eventManager->addEventListener(Events::onFlush, new SoftDeletableListener); 128 | 129 | $entityManager = EntityManager::create($connection_config, $metadata, $eventManager); 130 | $entityManager->getFilters()->enable('trashed'); 131 | return $entityManager; 132 | }); 133 | 134 | $this->app->alias(EntityManager::class, EntityManagerInterface::class); 135 | } 136 | 137 | private function registerClassMetadataFactory() 138 | { 139 | $this->app->singleton(ClassMetadataFactory::class, function ($app) { 140 | return $app[EntityManager::class]->getMetadataFactory(); 141 | }); 142 | } 143 | 144 | private function extendAuthManager() 145 | { 146 | $this->app[AuthManager::class]->extend('doctrine', function ($app) { 147 | return new DoctrineUserProvider( 148 | $app['Illuminate\Hashing\HasherInterface'], 149 | $app[EntityManager::class], 150 | $app['config']['auth.model'] 151 | ); 152 | }); 153 | } 154 | 155 | 156 | /** 157 | * Map Laravel's to Doctrine's database configuration requirements. 158 | * @param $config 159 | * @throws \Exception 160 | * @return array 161 | */ 162 | private function mapLaravelToDoctrineConfig($config) 163 | { 164 | $default = $config['database.default']; 165 | $connection = $config["database.connections.{$default}"]; 166 | return App::make(DriverMapper::class)->map($connection); 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /src/Traits/Authentication.php: -------------------------------------------------------------------------------- 1 | password; 17 | } 18 | 19 | public function setPassword($password) 20 | { 21 | $this->password = $password; 22 | } 23 | 24 | /** 25 | * Get the unique identifier for the user. 26 | * 27 | * @return mixed 28 | */ 29 | public function getAuthIdentifier() 30 | { 31 | return $this->getId(); 32 | } 33 | 34 | /** 35 | * Get the password for the user. 36 | * 37 | * @return string 38 | */ 39 | public function getAuthPassword() 40 | { 41 | return $this->getPassword(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/Traits/RememberToken.php: -------------------------------------------------------------------------------- 1 | rememberToken; 20 | } 21 | 22 | /** 23 | * Set the token value for the "remember me" session. 24 | * 25 | * @param string $value 26 | * @return void 27 | */ 28 | public function setRememberToken($value) 29 | { 30 | $this->rememberToken = $value; 31 | } 32 | 33 | /** 34 | * Get the column name for the "remember me" token. 35 | * 36 | * @return string 37 | */ 38 | public function getRememberTokenName() 39 | { 40 | return 'remember_token'; 41 | } 42 | 43 | /** 44 | * Get the e-mail address where password reminders are sent. 45 | * 46 | * @return string 47 | */ 48 | public function getReminderEmail() 49 | { 50 | return $this->email; 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /src/Traits/SoftDeletes.php: -------------------------------------------------------------------------------- 1 | deletedAt; 17 | } 18 | 19 | public function setDeletedAt(DateTime $deletedAt) 20 | { 21 | $this->deletedAt = $deletedAt; 22 | } 23 | 24 | public function isDeleted() 25 | { 26 | return new DateTime > $this->deletedAt; 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/Traits/Timestamps.php: -------------------------------------------------------------------------------- 1 | createdAt = $now; 27 | $this->updatedAt = $now; 28 | } 29 | 30 | /** 31 | * @ORM\PreUpdate 32 | */ 33 | public function preUpdate() 34 | { 35 | $this->updatedAt = new DateTime; 36 | } 37 | 38 | public function getCreatedAt() 39 | { 40 | return $this->createdAt; 41 | } 42 | 43 | public function setCreatedAt(DateTime $createdAt) 44 | { 45 | $this->createdAt = $createdAt; 46 | } 47 | 48 | public function getUpdatedAt() 49 | { 50 | return $this->updatedAt; 51 | } 52 | 53 | public function setUpdatedAt(DateTime $updatedAt) 54 | { 55 | $this->updatedAt = $updatedAt; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /src/Validation/DoctrinePresenceVerifier.php: -------------------------------------------------------------------------------- 1 | entityManager = $entityManager; 16 | } 17 | /** 18 | * Count the number of objects in a collection having the given value. 19 | * 20 | * @param string $collection 21 | * @param string $column 22 | * @param string $value 23 | * @param int $excludeId 24 | * @param string $idColumn 25 | * @param array $extra 26 | * @return int 27 | */ 28 | public function getCount($collection, $column, $value, $excludeId = null, $idColumn = null, array $extra = array()) 29 | { 30 | $queryParts = ['SELECT COUNT(*) FROM', $collection, 'WHERE', "$column = ?"]; 31 | 32 | if (!is_null($excludeId) && $excludeId != 'NULL') { 33 | $queryParts[] = 'AND '.($idColumn ?: 'id').' <> ?'; 34 | } 35 | 36 | foreach ($extra as $key => $extraValue) { 37 | $queryParts[] = "AND $key = ?"; 38 | } 39 | 40 | $query = $this->createQueryFrom($queryParts); 41 | $query->setParameter(1, $value); 42 | 43 | if (!is_null($excludeId) && $excludeId != 'NULL') { 44 | $query->setParameter(2, $excludeId); 45 | } 46 | 47 | foreach ($extra as $key => $extraValue) { 48 | $query->setParameter($key + 3, $extraValue); 49 | } 50 | 51 | return $query->getSingleScalarResult(); 52 | } 53 | 54 | /** 55 | * Count the number of objects in a collection with the given values. 56 | * 57 | * @param string $collection 58 | * @param string $column 59 | * @param array $values 60 | * @param array $extra 61 | * @return int 62 | */ 63 | public function getMultiCount($collection, $column, array $values, array $extra = array()) 64 | { 65 | $queryParts = ['SELECT COUNT(*) FROM', $collection, 'WHERE', "$column IN (?)"]; 66 | 67 | foreach ($extra as $key => $extraValue) { 68 | $queryParts[] = "AND $key = ?"; 69 | } 70 | 71 | $query = $this->createQueryFrom($queryParts); 72 | $query->setParameter(1, implode(',', $values)); 73 | 74 | foreach ($extra as $key => $extraValue) { 75 | $query->setParameter($key + 2, $extraValue); 76 | } 77 | 78 | return $query->count(); 79 | } 80 | 81 | /** 82 | * Creates a new Doctrine native query based on the query parts array. 83 | * 84 | * @param array $queryParts 85 | * @return mixed 86 | */ 87 | private function createQueryFrom(array $queryParts = []) 88 | { 89 | $rsm = new ResultSetMapping(); 90 | 91 | return $this->entityManager->createNativeQuery(implode(' ', $queryParts), $rsm); 92 | } 93 | } 94 | -------------------------------------------------------------------------------- /tests/Configuration/DriverMapperTest.php: -------------------------------------------------------------------------------- 1 | registerMapper($mockMapper1); 16 | $driverMapper->registerMapper($mockMapper2); 17 | 18 | $mockMapper1->shouldReceive('isAppropriateFor')->once()->andReturn(false); 19 | $mockMapper2->shouldReceive('isAppropriateFor')->once()->andReturn(true); 20 | $mockMapper2->shouldReceive('map')->once()->andReturn('mapped array'); 21 | 22 | $this->assertEquals('mapped array', $driverMapper->map([])); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /tests/Configuration/LaravelNamingStrategyTest.php: -------------------------------------------------------------------------------- 1 | laravelNamingStrategy = new LaravelNamingStrategy(new Str()); 17 | } 18 | 19 | public function testProperTableName() 20 | { 21 | // Singular namespaced StudlyCase class 22 | $className = 'Acme\\ClassName'; 23 | 24 | $tableName = $this->laravelNamingStrategy->classToTableName($className); 25 | 26 | // Plural, snake_cased table name 27 | $this->assertEquals('class_names', $tableName); 28 | } 29 | 30 | public function testProperColumnName() 31 | { 32 | // Columns derive from snakeCased fields 33 | $field = 'createdAt'; 34 | 35 | $columnName = $this->laravelNamingStrategy->propertyToColumnName($field); 36 | 37 | // And columns are just the snake_cased field 38 | $this->assertEquals('created_at', $columnName); 39 | } 40 | 41 | public function testProperColumnNameWithClassName() 42 | { 43 | // Columns derive from snakeCased fields 44 | $field = 'createdAt'; 45 | 46 | // Singular namespaced StudlyCase class 47 | $className = 'Acme\\ClassName'; 48 | 49 | $columnName = $this->laravelNamingStrategy->propertyToColumnName($field, $className); 50 | 51 | // Class name shouldn't affect how the column is called 52 | $this->assertEquals('created_at', $columnName); 53 | } 54 | 55 | public function testEmbeddedColumnName() 56 | { 57 | // Laravel doesn't have embeddeds 58 | $embeddedField = 'address'; 59 | $field = 'street1'; 60 | 61 | $columnName = $this->laravelNamingStrategy->embeddedFieldToColumnName($embeddedField, $field); 62 | 63 | // So this is just like Doctrine's default naming strategy 64 | $this->assertEquals('address_street1', $columnName); 65 | } 66 | 67 | public function testReferenceColumn() 68 | { 69 | // Laravel's convention is just 'id', like the default Doctrine 70 | $columnName = $this->laravelNamingStrategy->referenceColumnName(); 71 | 72 | $this->assertEquals('id', $columnName); 73 | } 74 | 75 | public function testJoinColumnName() 76 | { 77 | // Given a User -> belongsTo -> Group 78 | $field = 'group'; 79 | 80 | $columnName = $this->laravelNamingStrategy->joinColumnName($field); 81 | 82 | // We expect to have a group_id in the users table 83 | $this->assertEquals('group_id', $columnName); 84 | } 85 | 86 | public function testBelongsToManyJoinTable() 87 | { 88 | // Laravel doesn't do as Doctrine's default here 89 | $sourceModel = 'Acme\\ClassName'; 90 | 91 | // We don't care about "source" or "target" 92 | $targetModel = 'Acme\\AnotherClass'; 93 | 94 | // We should have it sorted by alphabetical order 95 | $tableName = $this->laravelNamingStrategy->joinTableName($sourceModel, $targetModel); 96 | $this->assertEquals('another_class_class_name', $tableName); 97 | 98 | // Let's test swapping parameters, just in case... 99 | $tableName = $this->laravelNamingStrategy->joinTableName($targetModel, $sourceModel); 100 | $this->assertEquals('another_class_class_name', $tableName); 101 | } 102 | 103 | public function testJoinKeyColumnName() 104 | { 105 | // This case is similar to Doctrine's default as well 106 | $className = 'Acme\\Foo'; 107 | 108 | // If no reference name is given, we use 'id' 109 | $columnName = $this->laravelNamingStrategy->joinKeyColumnName($className); 110 | 111 | // And expect singular_snake_id column 112 | $this->assertEquals('foo_id', $columnName); 113 | 114 | // Given a reference name 115 | $columnName = $this->laravelNamingStrategy->joinKeyColumnName($className, 'reference'); 116 | 117 | // Same thing, but with that reference instead of 'id' 118 | $this->assertEquals('foo_reference', $columnName); 119 | } 120 | } 121 | -------------------------------------------------------------------------------- /tests/Configuration/OCIMapperTest.php: -------------------------------------------------------------------------------- 1 | sqlMapper = new OCIMapper; 13 | } 14 | 15 | public function testAppropriation() 16 | { 17 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'oci8'])); 18 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'pdo_oci'])); 19 | } 20 | 21 | public function testMapping() 22 | { 23 | $configuration = [ 24 | 'driver' => 'oracle', 25 | 'host' => 'localhost', 26 | 'database' => 'db', 27 | 'username' => 'somedude', 28 | 'password' => 'not safe', 29 | 'prefix' => 'mitch_', 30 | 'charset' => 'whatevs', 31 | 'servicename' => 'SID' 32 | ]; 33 | 34 | $expected = [ 35 | 'pooled' => false, 36 | 'servicename' => 'SID', 37 | 'port' => 1521, 38 | 'driver' => 'oci8', 39 | 'host' => $configuration['host'], 40 | 'dbname' => $configuration['database'], 41 | 'user' => $configuration['username'], 42 | 'password' => $configuration['password'], 43 | 'charset' => $configuration['charset'], 44 | 'prefix' => $configuration['prefix'] 45 | ]; 46 | 47 | $actual = $this->sqlMapper->map($configuration); 48 | 49 | $this->assertEquals($expected, $actual); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /tests/Configuration/SqlMapperTest.php: -------------------------------------------------------------------------------- 1 | sqlMapper = new SqlMapper; 13 | } 14 | 15 | public function testAppropriation() 16 | { 17 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'mysql'])); 18 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'pgsql'])); 19 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'sqlsrv'])); 20 | } 21 | 22 | public function testMapping() 23 | { 24 | $configuration = [ 25 | 'driver' => 'mysql', 26 | 'host' => 'localhost', 27 | 'database' => 'db', 28 | 'username' => 'somedude', 29 | 'password' => 'not safe', 30 | 'prefix' => 'mitch_', 31 | 'charset' => 'whatevs' 32 | ]; 33 | $expected = [ 34 | 'driver' => 'pdo_mysql', 35 | 'host' => $configuration['host'], 36 | 'dbname' => $configuration['database'], 37 | 'user' => $configuration['username'], 38 | 'password' => $configuration['password'], 39 | 'charset' => $configuration['charset'], 40 | 'prefix' => $configuration['prefix'] 41 | ]; 42 | $actual = $this->sqlMapper->map($configuration); 43 | $this->assertEquals($expected, $actual); 44 | } 45 | 46 | public function testMappingWithoutPrefix() 47 | { 48 | $configuration = [ 49 | 'driver' => 'mysql', 50 | 'host' => 'localhost', 51 | 'database' => 'db', 52 | 'username' => 'somedude', 53 | 'password' => 'not safe', 54 | 'charset' => 'whatevs' 55 | ]; 56 | 57 | $expected = [ 58 | 'driver' => 'pdo_mysql', 59 | 'host' => $configuration['host'], 60 | 'dbname' => $configuration['database'], 61 | 'user' => $configuration['username'], 62 | 'password' => $configuration['password'], 63 | 'charset' => $configuration['charset'], 64 | 'prefix' => null 65 | ]; 66 | 67 | $actual = $this->sqlMapper->map($configuration); 68 | 69 | $this->assertEquals($expected, $actual); 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /tests/Configuration/SqliteMapperTest.php: -------------------------------------------------------------------------------- 1 | sqlMapper = new SqliteMapper; 15 | } 16 | 17 | public function testAppropriation() 18 | { 19 | $this->assertTrue($this->sqlMapper->isAppropriateFor(['driver' => 'sqlite'])); 20 | $this->assertFalse($this->sqlMapper->isAppropriateFor(['driver' => 'sqlsdfite'])); 21 | } 22 | 23 | public function testMapping() 24 | { 25 | Facade::setFacadeApplication(new ApplicationStub); 26 | $configuration = [ 27 | 'driver' => 'sqlite', 28 | 'database' => 'db', 29 | 'username' => 'somedude', 30 | 'prefix' => 'mitch_', 31 | 'charset' => 'whatevs' 32 | ]; 33 | 34 | $expected = [ 35 | 'driver' => 'pdo_sqlite', 36 | 'path' => $configuration['database'], 37 | 'user' => $configuration['username'], 38 | 'password' => null, 39 | 'prefix' => $configuration['prefix'] 40 | ]; 41 | $actual = $this->sqlMapper->map($configuration); 42 | $this->assertEquals($expected, $actual); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /tests/EventListener/TablePrefixTest.php: -------------------------------------------------------------------------------- 1 | metadata = new ClassMetadata('\Foo'); 12 | $this->metadata->setTableName('foo'); 13 | 14 | $this->objectManager = m::mock('Doctrine\Common\Persistence\ObjectManager'); 15 | 16 | $this->args = new \Doctrine\ORM\Event\LoadClassMetadataEventArgs($this->metadata, $this->objectManager); 17 | } 18 | 19 | /** 20 | * Basic prefix test 21 | */ 22 | public function testPrefixAdded() { 23 | 24 | $tablePrefix = new TablePrefix('someprefix_'); 25 | 26 | //call the listener 27 | $tablePrefix->loadClassMetadata($this->args); 28 | 29 | $this->assertEquals('someprefix_foo', $this->metadata->getTableName()); 30 | } 31 | 32 | /** 33 | * Oracle specific, autoincrements are done using sequences 34 | * this tests if the sequence also has the prefix - convinience 35 | */ 36 | public function testPrefixAddedToSequence() { 37 | 38 | $this->metadata->setSequenceGeneratorDefinition(array('sequenceName' => 'bar')); 39 | $this->metadata->setIdGeneratorType(ClassMetadata::GENERATOR_TYPE_SEQUENCE); 40 | 41 | $tablePrefix = new TablePrefix('someprefix_'); 42 | $tablePrefix->loadClassMetadata($this->args); 43 | 44 | $this->assertEquals('someprefix_foo', $this->metadata->getTableName()); 45 | $this->assertEquals(array('sequenceName' => 'someprefix_bar'), $this->metadata->sequenceGeneratorDefinition); 46 | 47 | } 48 | 49 | public function testManyToManyHasPrefix() { 50 | 51 | $this->metadata->mapManyToMany(array('fieldName' => 'fooBar', 'targetEntity' => 'bar')); 52 | 53 | $tablePrefix = new TablePrefix('someprefix_'); 54 | $tablePrefix->loadClassMetadata($this->args); 55 | 56 | $this->assertEquals('someprefix_foo', $this->metadata->getTableName()); 57 | $this->assertEquals('someprefix_foo_bar', $this->metadata->associationMappings['fooBar']['joinTable']['name']); 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /tests/Stubs/ApplicationStub.php: -------------------------------------------------------------------------------- 1 |