├── .gitignore ├── .travis.yml ├── tests ├── bootstrap.php └── Dflydev │ └── Tests │ └── IdentityGenerator │ └── DataStore │ └── Dbal │ └── DbalDataStoreTest.php ├── phpunit.xml.dist ├── LICENSE ├── composer.json ├── src └── Dflydev │ └── IdentityGenerator │ └── DataStore │ └── Dbal │ └── DataStore.php └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor 3 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: php 2 | 3 | php: 4 | - 5.3.3 5 | - 5.3 6 | - 5.4 7 | 8 | before_script: 9 | - wget -nc http://getcomposer.org/composer.phar 10 | - php composer.phar install --dev 11 | 12 | script: phpunit --coverage-text --verbose 13 | -------------------------------------------------------------------------------- /tests/bootstrap.php: -------------------------------------------------------------------------------- 1 | add('Dflydev\\Tests\\IdentityGenerator', 'tests'); 14 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ./tests/Dflydev/Tests/IdentityGenerator 6 | 7 | 8 | 9 | 10 | 11 | ./src/Dflydev/IdentityGenerator/ 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2012 Dragonfly Development Inc. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is furnished 8 | to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dflydev/identity-generator-dbal", 3 | "type": "library", 4 | "description": "Provides a Doctrine DBAL implementation of the identity generator data store.", 5 | "homepage": "https://github.com/dflydev/dflydev-identity-generator-dbal", 6 | "keywords": ["identity", "generator", "generation", "id", "dbal", "doctrine"], 7 | "license": "MIT", 8 | "authors": [ 9 | { 10 | "name": "Dragonfly Development Inc.", 11 | "email": "info@dflydev.com", 12 | "homepage": "http://dflydev.com" 13 | }, 14 | { 15 | "name": "Beau Simensen", 16 | "email": "beau@dflydev.com", 17 | "homepage": "http://beausimensen.com" 18 | } 19 | ], 20 | "require": { 21 | "php": ">=5.3.2", 22 | "dflydev/identity-generator": "1.*", 23 | "doctrine/dbal": ">=2.2.3,<2.4-dev" 24 | }, 25 | "autoload": { 26 | "psr-0": { 27 | "Dflydev\\IdentityGenerator\\DataStore\\Dbal": "src" 28 | } 29 | }, 30 | "extra": { 31 | "branch-alias": { 32 | "dev-master": "1.0-dev" 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Dflydev/IdentityGenerator/DataStore/Dbal/DataStore.php: -------------------------------------------------------------------------------- 1 | 24 | */ 25 | class DataStore implements DataStoreInterface 26 | { 27 | /** 28 | * Doctrine DBAL Connectcion 29 | * 30 | * @var Connection 31 | */ 32 | private $connection; 33 | 34 | /** 35 | * Table 36 | * 37 | * @var string 38 | */ 39 | private $table; 40 | 41 | /** 42 | * Column containing the identities 43 | * 44 | * @var string 45 | */ 46 | private $identityColumn; 47 | 48 | /** 49 | * Column containing the mobs 50 | * 51 | * @var string 52 | */ 53 | private $mobColumn; 54 | 55 | /** 56 | * Constructor 57 | * 58 | * @param Connection $connection Doctrine DBAL Connection 59 | * @param string $table Table 60 | * @param string $identityColumn Column containing the identities 61 | * @param string $mobColumn Column containing the mob 62 | */ 63 | public function __construct(Connection $connection, $table, $identityColumn, $mobColumn = null) 64 | { 65 | $this->connection = $connection; 66 | $this->table = $table; 67 | $this->identityColumn = $identityColumn; 68 | $this->mobColumn = $mobColumn; 69 | } 70 | 71 | /** 72 | * {@inheritdoc} 73 | */ 74 | public function storeIdentity($identity, $mob = null) 75 | { 76 | if (null !== $mob and null === $this->mobColumn) { 77 | throw new MobsUnsupportedException($identity, $mob, "Mob column is not defined."); 78 | } 79 | try { 80 | $map = array($this->identityColumn => $identity); 81 | if (null !== $mob) { 82 | $map[$this->mobColumn] = $mob; 83 | } 84 | 85 | $this->connection->insert($this->table, $map); 86 | } catch (\PDOException $e) { 87 | if ('23000' === $e->errorInfo[0]) { 88 | throw new NonUniqueIdentityException($identity, $mob); 89 | } 90 | 91 | throw new DataStoreException($e, $identity, $mob); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Doctrine DBAL Identity Generator Data Store 2 | =========================================== 3 | 4 | Provides a Doctrine DBAL implementation of the identity generator 5 | data store. For more information see: 6 | [dflydev/identity-generator](https://github.com/dflydev/dflydev-identity-generator) 7 | 8 | 9 | Requirements 10 | ------------ 11 | 12 | * PHP 5.3+ 13 | * Doctrine DBAL 2.2.* 14 | 15 | 16 | Implementation Details 17 | ---------------------- 18 | 19 | This simple dflydev/identity-generator Data Store implementation relies on 20 | blindly inserting records into a database. 21 | 22 | It works under the assumption that if the underlying database has a unique 23 | constraint configured for either an identity column or a unique constraint 24 | configured for both and identity and mob column an exception will be thrown. 25 | 26 | It attempts to capture this exception and determine whether or not there is a fault 27 | in the underlying connection or if it was due to a constraint violation. It 28 | does this by way of looking for ANSI SQL Error State Code `23000`. 29 | 30 | 31 | Schemas 32 | ------- 33 | 34 | The following are very naive examples of database schemas that will work with 35 | this data store. They may work for you for testing but please do not blindly 36 | use them for production. 37 | 38 | 39 | ### SQLite 40 | 41 | If mobs are not required simply create a table with one column marked as `unique`. 42 | 43 | CREATE TABLE identity ( 44 | identity string(64) unique 45 | ); 46 | 47 | If mobs are required create a table with two columns and create a unique constraint 48 | across both columns. 49 | 50 | CREATE TABLE identityWithMob ( 51 | identity string(64), 52 | mob string(64), 53 | constraint id unique (identity, mob) 54 | ); 55 | 56 | 57 | ### Mysql 58 | 59 | If mobs are not required simply create a table with one column marked as `unique`. 60 | 61 | CREATE TABLE identity ( 62 | identity varchar(64) unique 63 | ); 64 | 65 | If mobs are required create a table with two columns and create a unique index 66 | across both columns. 67 | 68 | CREATE TABLE identityWithMob ( 69 | identity varchar(64), 70 | mob varchar(64), 71 | unique index (identity, mob) 72 | ); 73 | 74 | 75 | Usage 76 | ----- 77 | 78 | use Dflydev\IdentityGenerator\DataStore\Dbal\DataStore; 79 | use Doctrine\DBAL\Configuration; 80 | use Doctrine\DBAL\DriverManager; 81 | 82 | $config = new Configuration(); 83 | $connectionParams = array(); // driver specific connection configuration 84 | $connection = DriverManager::getConnection($connectionParams, $config); 85 | 86 | // Create a Data Store that does not support a mob. 87 | $dataStore = new DataStore( 88 | $connection, 89 | 'tableName', 90 | 'identityColumnName' 91 | ); 92 | 93 | // Create a Data Store that supports a mob. 94 | $dataStoreWithMob = new DataStore( 95 | $connection, 96 | 'tableName', 97 | 'identityColumnName', 98 | 'mobColumnName' 99 | ); 100 | 101 | 102 | License 103 | ------- 104 | 105 | This library is licensed under the New BSD License - see the LICENSE file 106 | for details. 107 | 108 | 109 | Community 110 | --------- 111 | 112 | If you have questions or want to help out, join us in the 113 | [#dflydev](irc://irc.freenode.net/#dflydev) channel on irc.freenode.net. 114 | -------------------------------------------------------------------------------- /tests/Dflydev/Tests/IdentityGenerator/DataStore/Dbal/DbalDataStoreTest.php: -------------------------------------------------------------------------------- 1 | 24 | */ 25 | class DbalDataStoreTest extends \PHPUnit_Framework_TestCase 26 | { 27 | /** 28 | * Test connection throws unexpected exception 29 | */ 30 | public function testConnectionThrowsUnexpectedException() 31 | { 32 | $connection = $this 33 | ->getMockBuilder('Doctrine\DBAL\Connection') 34 | ->disableOriginalConstructor() 35 | ->getMock(); 36 | 37 | $connection 38 | ->expects($this->once()) 39 | ->method('insert') 40 | ->with($this->equalTo('identityTableName'), $this->equalTo(array('identityColumnName' => 'testIdentity'))) 41 | ->will($this->throwException(new \PDOException('Bogus Exception'))); 42 | 43 | $dataStore = new DataStore($connection, 'identityTableName', 'identityColumnName'); 44 | 45 | try { 46 | $dataStore->storeIdentity('testIdentity'); 47 | 48 | $this->fail('Connection should have thrown an exception'); 49 | } catch (DataStoreException $e) { 50 | $this->assertEquals('Bogus Exception', $e->getPrevious()->getMessage()); 51 | } 52 | } 53 | 54 | /** 55 | * Test connection throws constraint exception 56 | */ 57 | public function testConnectionThrowsConstraintException() 58 | { 59 | $connection = $this 60 | ->getMockBuilder('Doctrine\DBAL\Connection') 61 | ->disableOriginalConstructor() 62 | ->getMock(); 63 | 64 | $exception = new \PDOException('Bogus Exception'); 65 | $exception->errorInfo = array('23000'); 66 | 67 | $connection 68 | ->expects($this->once()) 69 | ->method('insert') 70 | ->with($this->equalTo('identityTableName'), $this->equalTo(array('identityColumnName' => 'testIdentity'))) 71 | ->will($this->throwException($exception)); 72 | 73 | $dataStore = new DataStore($connection, 'identityTableName', 'identityColumnName'); 74 | 75 | try { 76 | $dataStore->storeIdentity('testIdentity'); 77 | 78 | $this->fail('Connection should have thrown an exception'); 79 | } catch (NonUniqueIdentityException $e) { 80 | $this->assertEquals('Could not store generated identity as it is not unique: testIdentity', $e->getMessage()); 81 | } 82 | } 83 | 84 | /** 85 | * Test can store with no mob 86 | */ 87 | public function testCanStoreNoMob() 88 | { 89 | $connection = $this 90 | ->getMockBuilder('Doctrine\DBAL\Connection') 91 | ->disableOriginalConstructor() 92 | ->getMock(); 93 | 94 | $connection 95 | ->expects($this->once()) 96 | ->method('insert') 97 | ->with($this->equalTo('identityTableName'), $this->equalTo(array('identityColumnName' => 'testIdentity'))); 98 | 99 | $dataStore = new DataStore($connection, 'identityTableName', 'identityColumnName'); 100 | 101 | $dataStore->storeIdentity('testIdentity'); 102 | } 103 | 104 | /** 105 | * Test can store with mob 106 | */ 107 | public function testCanStoreMob() 108 | { 109 | $connection = $this 110 | ->getMockBuilder('Doctrine\DBAL\Connection') 111 | ->disableOriginalConstructor() 112 | ->getMock(); 113 | 114 | $connection 115 | ->expects($this->once()) 116 | ->method('insert') 117 | ->with( 118 | $this->equalTo('identityTableName'), 119 | $this->equalTo(array( 120 | 'identityColumnName' => 'testIdentity', 121 | 'mobColumnName' => 'testMob', 122 | )) 123 | ); 124 | 125 | $dataStore = new DataStore($connection, 'identityTableName', 'identityColumnName', 'mobColumnName'); 126 | 127 | $dataStore->storeIdentity('testIdentity', 'testMob'); 128 | } 129 | 130 | /** 131 | * Test cannot store mob when no mob configured 132 | */ 133 | public function testCannotStore() 134 | { 135 | $connection = $this 136 | ->getMockBuilder('Doctrine\DBAL\Connection') 137 | ->disableOriginalConstructor() 138 | ->getMock(); 139 | 140 | $dataStore = new DataStore($connection, 'identityTableName', 'identityColumnName'); 141 | 142 | try { 143 | $dataStore->storeIdentity('testIdentity', 'testMob'); 144 | 145 | $this->fail('Should not be able to store with a mob if no mob is configured'); 146 | } catch (MobsUnsupportedException $e) { 147 | $this->assertEquals( 148 | 'Mobs are unsupported under current configuration. Mob column is not defined. testIdentity (with mob testMob)', 149 | $e->getMessage() 150 | ); 151 | } 152 | } 153 | } 154 | --------------------------------------------------------------------------------