├── .gitignore
├── tests
├── schema5
│ ├── 002_drop.sql
│ └── 001_create.sql
├── schema3
│ ├── 1_bar.sql
│ └── 1_foo.sql
├── schema1
│ └── 1_test.sql
├── schema2
│ ├── 1_test.sql
│ └── 2_test.sql
├── schema4
│ └── 1_foo.sql
└── DBDeployPHP
│ └── DBDeployTest.php
├── phpunit.xml
├── .travis.yml
├── composer.json
├── bin
└── dbdeploy
├── src
└── DBDeployPHP
│ ├── MigrationStatus.php
│ ├── Command
│ └── MigrateCommand.php
│ └── DBDeploy.php
├── README.md
└── composer.lock
/.gitignore:
--------------------------------------------------------------------------------
1 | /vendor
2 |
--------------------------------------------------------------------------------
/tests/schema5/002_drop.sql:
--------------------------------------------------------------------------------
1 | DROP TABLE foo;
2 |
--------------------------------------------------------------------------------
/tests/schema3/1_bar.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INT);
2 |
--------------------------------------------------------------------------------
/tests/schema3/1_foo.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INT);
2 |
--------------------------------------------------------------------------------
/tests/schema1/1_test.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INTEGER);
2 |
--------------------------------------------------------------------------------
/tests/schema2/1_test.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INTEGER);
2 |
--------------------------------------------------------------------------------
/tests/schema2/2_test.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE bar (id INTEGER);
2 |
--------------------------------------------------------------------------------
/tests/schema5/001_create.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INTEGER);
2 |
--------------------------------------------------------------------------------
/tests/schema4/1_foo.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE foo (id INT);
2 | --//@UNDO
3 | DROP TABLE foo;
4 |
--------------------------------------------------------------------------------
/phpunit.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | tests/
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: php
2 |
3 | php:
4 | - 5.4
5 | - 5.5
6 | - 5.6
7 |
8 | env:
9 | - DATABASE_URL="mysql://travis@127.0.0.1/dbdeploy"
10 |
11 | before_script:
12 | - mysql -uroot -e "CREATE DATABASE dbdeploy"
13 | - composer install
14 |
15 | script: phpunit
16 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "beberlei/dbdeploy-php",
3 | "license": "MIT",
4 | "autoload": {
5 | "psr-0": {"DBDeployPHP": "src/"}
6 | },
7 | "require": {
8 | "doctrine/dbal": "~2.5",
9 | "php": "~5.4"
10 | },
11 | "bin": ["bin/dbdeploy"]
12 | }
13 |
--------------------------------------------------------------------------------
/bin/dbdeploy:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 | add(new Command\MigrateCommand());
34 | $application->run();
35 |
--------------------------------------------------------------------------------
/src/DBDeployPHP/MigrationStatus.php:
--------------------------------------------------------------------------------
1 | all = $all;
25 | $this->applied = $applied;
26 | $this->apply = $apply;
27 | }
28 |
29 | public function getAllMigrations()
30 | {
31 | return $this->all;
32 | }
33 |
34 | public function getApplyMigrations()
35 | {
36 | return $this->apply;
37 | }
38 |
39 | public function getAppliedMigrations()
40 | {
41 | return $this->applied;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/src/DBDeployPHP/Command/MigrateCommand.php:
--------------------------------------------------------------------------------
1 | setName('migrate')
20 | ->setDescription('Migrate a given database to the latest version.')
21 | ->addArgument('schema-dir', InputArgument::REQUIRED)
22 | ->addOption('dsn', 'd', InputOption::VALUE_REQUIRED)
23 | ;
24 | }
25 |
26 | protected function execute(InputInterface $input, OutputInterface $output)
27 | {
28 | $directory = $input->getArgument('schema-dir');
29 |
30 | if (strpos($directory, '/') !== 0) {
31 | $directory = getcwd() . '/' . $directory;
32 | }
33 |
34 | if (!file_exists($directory)) {
35 | throw new RuntimeException(sprintf("Schema directory does not exist at '%s'.", $directory));
36 | }
37 |
38 | $dsn = $input->getOption('dsn');
39 |
40 | if (isset($_SERVER['DATABASE_URL'])) {
41 | $dsn = $_SERVER['DATABASE_URL'];
42 | }
43 |
44 | if (!$dsn) {
45 | throw new RuntimeException("Missing environment variable DATABASE_URL in format mysql://user:password@host/database");
46 | }
47 |
48 | $connection = DriverManager::getConnection(array('url' => $_SERVER['DATABASE_URL']));
49 | $migrator = new DBDeploy($connection, $directory);
50 |
51 | $output->writeln(sprintf("Reading change scripts from directory %s... \n", $directory));
52 |
53 | $status = $migrator->getCurrentStatus();
54 |
55 | $appliedString = $status->getAppliedMigrations() ? implode(', ', array_keys($status->getAppliedMigrations())) : '(none)';
56 | $applyString = $status->getApplyMigrations() ? implode(', ', array_keys($status->getApplyMigrations())) : '(none)';
57 |
58 | $output->writeln(sprintf("Changes currently applied to database:\n %s\n", $appliedString));
59 | $output->writeln(sprintf("To be applied:\n %s", $applyString));
60 |
61 | $migrator->apply($status);
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DBDeploy PHP
2 |
3 | [](https://travis-ci.org/beberlei/dbdeploy-php)
4 |
5 | This is a clone of [DBDeploy](http://dbdeploy.com) for PHP using Doctrine DBAL
6 | as database abstraction.
7 |
8 | It supports only a limited set of functionality of the original Java based
9 | tool, but enough for one particular workflow to function perfectly.
10 |
11 | Why? This is extracted from a testsuite where it was used for setting up the
12 | schema of the testing database. It is also much easier to setup than DBDeploy.
13 |
14 | ## Workflow Assumptions
15 |
16 | * Only .sql file based migrations, format `_.sql`
17 | * Requires using backwards-compatible database changes, no support undo/down
18 | migrations. Especially
19 | * Avoid dropping stuff
20 | * Added column must either allow NULL or have a default value
21 | * Orders migrations (natural sort) using number prefixes in files. Use
22 | `YYmmddHHii_.sql` format to allow branching without conflicts.
23 | * Single database vendor per directory, use multiple for apps with different
24 | vendor support.
25 | * Creates table `changelog` that contains current state of already applied migrations.
26 |
27 | ## API
28 |
29 | The API just has one method: `migrate()`:
30 |
31 | ```php
32 | migrate();
39 | ```
40 | ## CLI
41 |
42 | You need environment variable `DATABASE_URL` present with the format: `mysql://user:password@host/dbname`:
43 |
44 | $ php vendor/bin/dbdeploy-migrate.php src/schema
45 |
46 | ## Limitations
47 |
48 | Currently only works with MySQL.
49 |
50 | ## License
51 |
52 | The MIT License (MIT)
53 |
54 | Copyright (c) 2015 Benjamin Eberlei
55 |
56 | Permission is hereby granted, free of charge, to any person obtaining a copy
57 | of this software and associated documentation files (the "Software"), to deal
58 | in the Software without restriction, including without limitation the rights
59 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
60 | copies of the Software, and to permit persons to whom the Software is
61 | furnished to do so, subject to the following conditions:
62 |
63 | The above copyright notice and this permission notice shall be included in
64 | all copies or substantial portions of the Software.
65 |
66 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
67 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
68 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
69 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
70 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
71 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
72 | THE SOFTWARE.
73 |
--------------------------------------------------------------------------------
/tests/DBDeployPHP/DBDeployTest.php:
--------------------------------------------------------------------------------
1 | markTestSkipped('Requires DBDEPLOY_TEST_DATABASE_URL env variable for a connection (not directly to a database)');
19 | }
20 |
21 | $connection = DriverManager::getConnection(array(
22 | 'url' => $_SERVER['DBDEPLOY_TEST_DATABASE_URL'],
23 | ));
24 | $connection->exec('CREATE DATABASE IF NOT EXISTS ' . self::$databaseName);
25 | $connection->exec('USE ' . self::$databaseName);
26 |
27 | return $connection;
28 | }
29 |
30 | /**
31 | * @test
32 | */
33 | public function it_migrates()
34 | {
35 | $connection = $this->createConnection();
36 | $schemaManager = $connection->getSchemaManager();
37 |
38 | $schemaManager->tryMethod('dropTable', 'foo');
39 | $schemaManager->tryMethod('dropTable', 'bar');
40 | $schemaManager->tryMethod('dropTable', 'changelog');
41 |
42 | $deploy = new DBDeploy($connection, __DIR__ . '/../schema1');
43 | $deploy->migrate();
44 |
45 | $this->assertEquals(array('changelog', 'foo'), $schemaManager->listTableNames());
46 |
47 | $deploy = new DBDeploy($connection, __DIR__ . '/../schema2');
48 | $deploy->migrate();
49 |
50 | $this->assertEquals(array('bar', 'changelog', 'foo'), $schemaManager->listTableNames());
51 | }
52 |
53 | /**
54 | * @test
55 | */
56 | public function it_requires_schema_manager()
57 | {
58 | $connection = DriverManager::getConnection(array('url' => 'sqlite://memory'));
59 |
60 | $this->setExpectedException('RuntimeException', 'SchemaDirectory ');
61 |
62 | new DBDeploy($connection, __DIR__ . '/doesnotexist');
63 | }
64 |
65 | /**
66 | * @test
67 | */
68 | public function it_disallows_duplicate_revisions()
69 | {
70 | $connection = $this->createConnection();
71 |
72 | $this->setExpectedException('RuntimeException', "Duplicate revision number '1' is not allowed.");
73 |
74 | $deploy = new DBDeploy($connection, __DIR__ . '/../schema3');
75 | $deploy->migrate();
76 | }
77 |
78 | /**
79 | * @test
80 | */
81 | public function it_disallows_undo_dbdeploy_files()
82 | {
83 | $connection = $this->createConnection();
84 |
85 | $this->setExpectedException('RuntimeException', 'No support for DBDeploy "--//@UNDO" feature.');
86 |
87 | $deploy = new DBDeploy($connection, __DIR__ . '/../schema4');
88 | $deploy->migrate();
89 | }
90 |
91 | /**
92 | * @test
93 | */
94 | public function it_natuarlly_sorts()
95 | {
96 | $connection = $this->createConnection();
97 | $schemaManager = $connection->getSchemaManager();
98 |
99 | $schemaManager->tryMethod('dropTable', 'foo');
100 | $schemaManager->tryMethod('dropTable', 'bar');
101 | $schemaManager->tryMethod('dropTable', 'changelog');
102 |
103 | $deploy = new DBDeploy($connection, __DIR__ . '/../schema5');
104 | $deploy->migrate();
105 |
106 | $migrations = array_map(function ($row) {
107 | return $row['description'];
108 | }, $connection->fetchAll('SELECT description FROM changelog'));
109 |
110 | $this->assertEquals(array('changelog'), $schemaManager->listTableNames());
111 | $this->assertEquals(array('001_create.sql', '002_drop.sql'), $migrations);
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/src/DBDeployPHP/DBDeploy.php:
--------------------------------------------------------------------------------
1 | connection = $connection;
46 | $this->schemaDirectory = $schemaDirectory;
47 | }
48 |
49 | /**
50 | * Return Current Migration Status of the database.
51 | *
52 | * @return MigrationStatus
53 | */
54 | public function getCurrentStatus()
55 | {
56 | $schemaManager = $this->connection->getSchemaManager();
57 | $tables = $schemaManager->listTableNames();
58 |
59 | if (!in_array('changelog', $tables)) {
60 | $table = new \Doctrine\DBAL\Schema\Table('changelog');
61 | $table->addColumn('change_number', 'integer');
62 | $table->addColumn('complete_dt', 'datetime', array(
63 | 'columnDefinition' => 'TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP',
64 | ));
65 | $table->addColumn('applied_by', 'string', array('length' => 100));
66 | $table->addcolumn('description', 'string', array('length' => 500));
67 | $table->setPrimaryKey(array('change_number'));
68 |
69 | $schemaManager->createTable($table);
70 | }
71 |
72 | $allMigrations = $this->getAllMigrations($this->schemaDirectory);
73 | $appliedMigrations = $this->getAppliedMigrations();
74 | $applyMigrations = array();
75 |
76 | foreach ($allMigrations as $revision => $data) {
77 | if (!isset($appliedMigrations[$revision])) {
78 | $applyMigrations[$revision] = $data;
79 | }
80 | }
81 |
82 | return new MigrationStatus($allMigrations, $appliedMigrations, $applyMigrations);
83 | }
84 |
85 | /**
86 | * Migrate database to new version comparing changelog table and schema directory.
87 | *
88 | * @return array
89 | */
90 | public function migrate()
91 | {
92 | $status = $this->getCurrentStatus();
93 | $this->apply($status);
94 |
95 | return $status->getApplyMigrations();
96 | }
97 |
98 | /**
99 | * Apply a migration status with unapplied changes to the database.
100 | *
101 | * @param MigrationStatus $status
102 | */
103 | public function apply(MigrationStatus $status)
104 | {
105 | foreach ($status->getApplyMigrations() as $revision => $data) {
106 | $this->connection->exec($data['sql']);
107 | $this->connection->insert(
108 | 'changelog',
109 | array(
110 | 'change_number' => $data['change_number'],
111 | 'description' => $data['description'],
112 | 'applied_by' => $data['applied_by']
113 | )
114 | );
115 | }
116 | }
117 |
118 | private function getAllMigrations($path)
119 | {
120 | $files = glob($path . '/*.sql');
121 | $migrations = array();
122 |
123 | foreach ($files as $file) {
124 | $basefile = basename($file);
125 | $sql = file_get_contents($file);
126 |
127 | $revision = $this->getRevision($basefile);
128 |
129 | if (isset($migrations[$revision])) {
130 | throw new \RuntimeException(sprintf("Duplicate revision number '%d' is not allowed.", $revision));
131 | }
132 |
133 | if (strpos($sql, '--//@UNDO') !== false) {
134 | throw new \RuntimeException('No support for DBDeploy "--//@UNDO" feature.');
135 | }
136 |
137 | $migrations[$revision] = array(
138 | 'change_number' => $revision,
139 | 'sql' => $sql,
140 | 'file' => $file,
141 | 'description' => $basefile,
142 | 'applied_by' => $this->connection->getUsername(),
143 | );
144 | }
145 |
146 | ksort($migrations, SORT_NATURAL);
147 |
148 | return $migrations;
149 | }
150 |
151 | private function getAppliedMigrations()
152 | {
153 | $appliedMigrations = array();
154 |
155 | $sql = 'SELECT * FROM changelog';
156 | $stmt = $this->connection->executeQuery($sql);
157 |
158 | while ($row = $stmt->fetch()) {
159 | $revision = $this->getRevision($row['description']);
160 |
161 | if (isset($appliedMigrations[$revision])) {
162 | throw new \RuntimeException(sprintf("Duplicate revision number '%d' is not allowed.", $revision));
163 | }
164 |
165 | $appliedMigrations[$revision] = $row;
166 | }
167 |
168 | return $appliedMigrations;
169 | }
170 |
171 | private function getRevision($basefile)
172 | {
173 | if (preg_match('((^[0-9]+)_(.*)$)', $basefile, $matches)) {
174 | return $matches[1];
175 | } else {
176 | throw new \RuntimeException(sprintf("No revision found in file '%s'.", $basefile));
177 | }
178 | }
179 | }
180 |
--------------------------------------------------------------------------------
/composer.lock:
--------------------------------------------------------------------------------
1 | {
2 | "_readme": [
3 | "This file locks the dependencies of your project to a known state",
4 | "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
5 | "This file is @generated automatically"
6 | ],
7 | "hash": "2208544f70bfdfd04c4975112e3a4570",
8 | "packages": [
9 | {
10 | "name": "doctrine/annotations",
11 | "version": "v1.2.3",
12 | "source": {
13 | "type": "git",
14 | "url": "https://github.com/doctrine/annotations.git",
15 | "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4"
16 | },
17 | "dist": {
18 | "type": "zip",
19 | "url": "https://api.github.com/repos/doctrine/annotations/zipball/eeda578cbe24a170331a1cfdf78be723412df7a4",
20 | "reference": "eeda578cbe24a170331a1cfdf78be723412df7a4",
21 | "shasum": ""
22 | },
23 | "require": {
24 | "doctrine/lexer": "1.*",
25 | "php": ">=5.3.2"
26 | },
27 | "require-dev": {
28 | "doctrine/cache": "1.*",
29 | "phpunit/phpunit": "4.*"
30 | },
31 | "type": "library",
32 | "extra": {
33 | "branch-alias": {
34 | "dev-master": "1.3.x-dev"
35 | }
36 | },
37 | "autoload": {
38 | "psr-0": {
39 | "Doctrine\\Common\\Annotations\\": "lib/"
40 | }
41 | },
42 | "notification-url": "https://packagist.org/downloads/",
43 | "license": [
44 | "MIT"
45 | ],
46 | "authors": [
47 | {
48 | "name": "Roman Borschel",
49 | "email": "roman@code-factory.org"
50 | },
51 | {
52 | "name": "Benjamin Eberlei",
53 | "email": "kontakt@beberlei.de"
54 | },
55 | {
56 | "name": "Guilherme Blanco",
57 | "email": "guilhermeblanco@gmail.com"
58 | },
59 | {
60 | "name": "Jonathan Wage",
61 | "email": "jonwage@gmail.com"
62 | },
63 | {
64 | "name": "Johannes Schmitt",
65 | "email": "schmittjoh@gmail.com"
66 | }
67 | ],
68 | "description": "Docblock Annotations Parser",
69 | "homepage": "http://www.doctrine-project.org",
70 | "keywords": [
71 | "annotations",
72 | "docblock",
73 | "parser"
74 | ],
75 | "time": "2014-12-20 20:49:38"
76 | },
77 | {
78 | "name": "doctrine/cache",
79 | "version": "v1.4.0",
80 | "source": {
81 | "type": "git",
82 | "url": "https://github.com/doctrine/cache.git",
83 | "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8"
84 | },
85 | "dist": {
86 | "type": "zip",
87 | "url": "https://api.github.com/repos/doctrine/cache/zipball/2346085d2b027b233ae1d5de59b07440b9f288c8",
88 | "reference": "2346085d2b027b233ae1d5de59b07440b9f288c8",
89 | "shasum": ""
90 | },
91 | "require": {
92 | "php": ">=5.3.2"
93 | },
94 | "conflict": {
95 | "doctrine/common": ">2.2,<2.4"
96 | },
97 | "require-dev": {
98 | "phpunit/phpunit": ">=3.7",
99 | "predis/predis": "~0.8",
100 | "satooshi/php-coveralls": "~0.6"
101 | },
102 | "type": "library",
103 | "extra": {
104 | "branch-alias": {
105 | "dev-master": "1.4.x-dev"
106 | }
107 | },
108 | "autoload": {
109 | "psr-0": {
110 | "Doctrine\\Common\\Cache\\": "lib/"
111 | }
112 | },
113 | "notification-url": "https://packagist.org/downloads/",
114 | "license": [
115 | "MIT"
116 | ],
117 | "authors": [
118 | {
119 | "name": "Roman Borschel",
120 | "email": "roman@code-factory.org"
121 | },
122 | {
123 | "name": "Benjamin Eberlei",
124 | "email": "kontakt@beberlei.de"
125 | },
126 | {
127 | "name": "Guilherme Blanco",
128 | "email": "guilhermeblanco@gmail.com"
129 | },
130 | {
131 | "name": "Jonathan Wage",
132 | "email": "jonwage@gmail.com"
133 | },
134 | {
135 | "name": "Johannes Schmitt",
136 | "email": "schmittjoh@gmail.com"
137 | }
138 | ],
139 | "description": "Caching library offering an object-oriented API for many cache backends",
140 | "homepage": "http://www.doctrine-project.org",
141 | "keywords": [
142 | "cache",
143 | "caching"
144 | ],
145 | "time": "2015-01-15 20:38:55"
146 | },
147 | {
148 | "name": "doctrine/collections",
149 | "version": "v1.2",
150 | "source": {
151 | "type": "git",
152 | "url": "https://github.com/doctrine/collections.git",
153 | "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2"
154 | },
155 | "dist": {
156 | "type": "zip",
157 | "url": "https://api.github.com/repos/doctrine/collections/zipball/b99c5c46c87126201899afe88ec490a25eedd6a2",
158 | "reference": "b99c5c46c87126201899afe88ec490a25eedd6a2",
159 | "shasum": ""
160 | },
161 | "require": {
162 | "php": ">=5.3.2"
163 | },
164 | "type": "library",
165 | "extra": {
166 | "branch-alias": {
167 | "dev-master": "1.2.x-dev"
168 | }
169 | },
170 | "autoload": {
171 | "psr-0": {
172 | "Doctrine\\Common\\Collections\\": "lib/"
173 | }
174 | },
175 | "notification-url": "https://packagist.org/downloads/",
176 | "license": [
177 | "MIT"
178 | ],
179 | "authors": [
180 | {
181 | "name": "Jonathan Wage",
182 | "email": "jonwage@gmail.com",
183 | "homepage": "http://www.jwage.com/",
184 | "role": "Creator"
185 | },
186 | {
187 | "name": "Guilherme Blanco",
188 | "email": "guilhermeblanco@gmail.com",
189 | "homepage": "http://www.instaclick.com"
190 | },
191 | {
192 | "name": "Roman Borschel",
193 | "email": "roman@code-factory.org"
194 | },
195 | {
196 | "name": "Benjamin Eberlei",
197 | "email": "kontakt@beberlei.de"
198 | },
199 | {
200 | "name": "Johannes Schmitt",
201 | "email": "schmittjoh@gmail.com",
202 | "homepage": "https://github.com/schmittjoh",
203 | "role": "Developer of wrapped JMSSerializerBundle"
204 | }
205 | ],
206 | "description": "Collections Abstraction library",
207 | "homepage": "http://www.doctrine-project.org",
208 | "keywords": [
209 | "array",
210 | "collections",
211 | "iterator"
212 | ],
213 | "time": "2014-02-03 23:07:43"
214 | },
215 | {
216 | "name": "doctrine/common",
217 | "version": "v2.4.2",
218 | "source": {
219 | "type": "git",
220 | "url": "https://github.com/doctrine/common.git",
221 | "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b"
222 | },
223 | "dist": {
224 | "type": "zip",
225 | "url": "https://api.github.com/repos/doctrine/common/zipball/5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
226 | "reference": "5db6ab40e4c531f14dad4ca96a394dfce5d4255b",
227 | "shasum": ""
228 | },
229 | "require": {
230 | "doctrine/annotations": "1.*",
231 | "doctrine/cache": "1.*",
232 | "doctrine/collections": "1.*",
233 | "doctrine/inflector": "1.*",
234 | "doctrine/lexer": "1.*",
235 | "php": ">=5.3.2"
236 | },
237 | "require-dev": {
238 | "phpunit/phpunit": "~3.7"
239 | },
240 | "type": "library",
241 | "extra": {
242 | "branch-alias": {
243 | "dev-master": "2.4.x-dev"
244 | }
245 | },
246 | "autoload": {
247 | "psr-0": {
248 | "Doctrine\\Common\\": "lib/"
249 | }
250 | },
251 | "notification-url": "https://packagist.org/downloads/",
252 | "license": [
253 | "MIT"
254 | ],
255 | "authors": [
256 | {
257 | "name": "Jonathan Wage",
258 | "email": "jonwage@gmail.com",
259 | "homepage": "http://www.jwage.com/",
260 | "role": "Creator"
261 | },
262 | {
263 | "name": "Guilherme Blanco",
264 | "email": "guilhermeblanco@gmail.com",
265 | "homepage": "http://www.instaclick.com"
266 | },
267 | {
268 | "name": "Roman Borschel",
269 | "email": "roman@code-factory.org"
270 | },
271 | {
272 | "name": "Benjamin Eberlei",
273 | "email": "kontakt@beberlei.de"
274 | },
275 | {
276 | "name": "Johannes Schmitt",
277 | "email": "schmittjoh@gmail.com",
278 | "homepage": "https://github.com/schmittjoh",
279 | "role": "Developer of wrapped JMSSerializerBundle"
280 | }
281 | ],
282 | "description": "Common Library for Doctrine projects",
283 | "homepage": "http://www.doctrine-project.org",
284 | "keywords": [
285 | "annotations",
286 | "collections",
287 | "eventmanager",
288 | "persistence",
289 | "spl"
290 | ],
291 | "time": "2014-05-21 19:28:51"
292 | },
293 | {
294 | "name": "doctrine/dbal",
295 | "version": "v2.5.1",
296 | "source": {
297 | "type": "git",
298 | "url": "https://github.com/doctrine/dbal.git",
299 | "reference": "628c2256b646ae2417d44e063bce8aec5199d48d"
300 | },
301 | "dist": {
302 | "type": "zip",
303 | "url": "https://api.github.com/repos/doctrine/dbal/zipball/628c2256b646ae2417d44e063bce8aec5199d48d",
304 | "reference": "628c2256b646ae2417d44e063bce8aec5199d48d",
305 | "shasum": ""
306 | },
307 | "require": {
308 | "doctrine/common": ">=2.4,<2.6-dev",
309 | "php": ">=5.3.2"
310 | },
311 | "require-dev": {
312 | "phpunit/phpunit": "4.*",
313 | "symfony/console": "2.*"
314 | },
315 | "suggest": {
316 | "symfony/console": "For helpful console commands such as SQL execution and import of files."
317 | },
318 | "bin": [
319 | "bin/doctrine-dbal"
320 | ],
321 | "type": "library",
322 | "extra": {
323 | "branch-alias": {
324 | "dev-master": "2.5.x-dev"
325 | }
326 | },
327 | "autoload": {
328 | "psr-0": {
329 | "Doctrine\\DBAL\\": "lib/"
330 | }
331 | },
332 | "notification-url": "https://packagist.org/downloads/",
333 | "license": [
334 | "MIT"
335 | ],
336 | "authors": [
337 | {
338 | "name": "Roman Borschel",
339 | "email": "roman@code-factory.org"
340 | },
341 | {
342 | "name": "Benjamin Eberlei",
343 | "email": "kontakt@beberlei.de"
344 | },
345 | {
346 | "name": "Guilherme Blanco",
347 | "email": "guilhermeblanco@gmail.com"
348 | },
349 | {
350 | "name": "Jonathan Wage",
351 | "email": "jonwage@gmail.com"
352 | }
353 | ],
354 | "description": "Database Abstraction Layer",
355 | "homepage": "http://www.doctrine-project.org",
356 | "keywords": [
357 | "database",
358 | "dbal",
359 | "persistence",
360 | "queryobject"
361 | ],
362 | "time": "2015-01-12 21:52:47"
363 | },
364 | {
365 | "name": "doctrine/inflector",
366 | "version": "v1.0.1",
367 | "source": {
368 | "type": "git",
369 | "url": "https://github.com/doctrine/inflector.git",
370 | "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604"
371 | },
372 | "dist": {
373 | "type": "zip",
374 | "url": "https://api.github.com/repos/doctrine/inflector/zipball/0bcb2e79d8571787f18b7eb036ed3d004908e604",
375 | "reference": "0bcb2e79d8571787f18b7eb036ed3d004908e604",
376 | "shasum": ""
377 | },
378 | "require": {
379 | "php": ">=5.3.2"
380 | },
381 | "require-dev": {
382 | "phpunit/phpunit": "4.*"
383 | },
384 | "type": "library",
385 | "extra": {
386 | "branch-alias": {
387 | "dev-master": "1.0.x-dev"
388 | }
389 | },
390 | "autoload": {
391 | "psr-0": {
392 | "Doctrine\\Common\\Inflector\\": "lib/"
393 | }
394 | },
395 | "notification-url": "https://packagist.org/downloads/",
396 | "license": [
397 | "MIT"
398 | ],
399 | "authors": [
400 | {
401 | "name": "Roman Borschel",
402 | "email": "roman@code-factory.org"
403 | },
404 | {
405 | "name": "Benjamin Eberlei",
406 | "email": "kontakt@beberlei.de"
407 | },
408 | {
409 | "name": "Guilherme Blanco",
410 | "email": "guilhermeblanco@gmail.com"
411 | },
412 | {
413 | "name": "Jonathan Wage",
414 | "email": "jonwage@gmail.com"
415 | },
416 | {
417 | "name": "Johannes Schmitt",
418 | "email": "schmittjoh@gmail.com"
419 | }
420 | ],
421 | "description": "Common String Manipulations with regard to casing and singular/plural rules.",
422 | "homepage": "http://www.doctrine-project.org",
423 | "keywords": [
424 | "inflection",
425 | "pluralize",
426 | "singularize",
427 | "string"
428 | ],
429 | "time": "2014-12-20 21:24:13"
430 | },
431 | {
432 | "name": "doctrine/lexer",
433 | "version": "v1.0.1",
434 | "source": {
435 | "type": "git",
436 | "url": "https://github.com/doctrine/lexer.git",
437 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c"
438 | },
439 | "dist": {
440 | "type": "zip",
441 | "url": "https://api.github.com/repos/doctrine/lexer/zipball/83893c552fd2045dd78aef794c31e694c37c0b8c",
442 | "reference": "83893c552fd2045dd78aef794c31e694c37c0b8c",
443 | "shasum": ""
444 | },
445 | "require": {
446 | "php": ">=5.3.2"
447 | },
448 | "type": "library",
449 | "extra": {
450 | "branch-alias": {
451 | "dev-master": "1.0.x-dev"
452 | }
453 | },
454 | "autoload": {
455 | "psr-0": {
456 | "Doctrine\\Common\\Lexer\\": "lib/"
457 | }
458 | },
459 | "notification-url": "https://packagist.org/downloads/",
460 | "license": [
461 | "MIT"
462 | ],
463 | "authors": [
464 | {
465 | "name": "Roman Borschel",
466 | "email": "roman@code-factory.org"
467 | },
468 | {
469 | "name": "Guilherme Blanco",
470 | "email": "guilhermeblanco@gmail.com"
471 | },
472 | {
473 | "name": "Johannes Schmitt",
474 | "email": "schmittjoh@gmail.com"
475 | }
476 | ],
477 | "description": "Base library for a lexer that can be used in Top-Down, Recursive Descent Parsers.",
478 | "homepage": "http://www.doctrine-project.org",
479 | "keywords": [
480 | "lexer",
481 | "parser"
482 | ],
483 | "time": "2014-09-09 13:34:57"
484 | }
485 | ],
486 | "packages-dev": [],
487 | "aliases": [],
488 | "minimum-stability": "stable",
489 | "stability-flags": [],
490 | "prefer-stable": false,
491 | "prefer-lowest": false,
492 | "platform": {
493 | "php": "~5.4"
494 | },
495 | "platform-dev": []
496 | }
497 |
--------------------------------------------------------------------------------