pax_global_header 0000666 0000000 0000000 00000000064 13217376123 0014517 g ustar 00root root 0000000 0000000 52 comment=e1698319ad55157c233b658c08f7a10617e797ca
phinx-0.9.2/ 0000775 0000000 0000000 00000000000 13217376123 0012655 5 ustar 00root root 0000000 0000000 phinx-0.9.2/CHANGELOG.md 0000664 0000000 0000000 00000044526 13217376123 0014501 0 ustar 00root root 0000000 0000000 # Version History
**0.9.2** (Saturday, 23 December 2017)
* Pull requests
* [#1169](https://github.com/cakephp/phinx/pull/1169) Apply default collation on tables as per documentation
* [#1214](https://github.com/cakephp/phinx/pull/1214) Simplify multiple primary key quoting
* [#1238](https://github.com/cakephp/phinx/pull/1238) Support PHPUnit 6
* [#1244](https://github.com/cakephp/phinx/pull/1244) Add ordered seeds feature
* [#1246](https://github.com/cakephp/phinx/pull/1246) Added saving column's comment for PostgresAdapter when you add column
* Bug fixes
* [#1181](https://github.com/cakephp/phinx/pull/1181) Fix "Fatal: hasOption() on null" error
* [#1198](https://github.com/cakephp/phinx/pull/1198) Fix chainability for the setColumns call
**0.9.1** (Satruday, 9 September 2017)
* Pull requests
* [#1164](https://github.com/robmorgan/phinx/pull/1164) Added a function to migration classes to determine migration direction
* Bug fixes
* [#1173](https://github.com/cakephp/phinx/pull/1173) Fixing configuration item `default_migration_table`
* [#1170](https://github.com/cakephp/phinx/pull/1170) Fixed regression when setting the pdo object directly in the config
**0.9.0** (Sunday, 3rd September 2017)
* Documentation updates
* Pull requests
* [#1122](https://github.com/robmorgan/phinx/pull/1129) SQL exceptions will now produce PHP exceptions
* [#1053](https://github.com/robmorgan/phinx/pull/1053) Docker Development Kickstarter
* [#945](https://github.com/robmorgan/phinx/pull/945) Rollback --target using migration name
* [#1070](https://github.com/robmorgan/phinx/pull/1070) Supporting namespaces in configuration, Migrations and Seeds
* [#1155](https://github.com/robmorgan/phinx/pull/1155) Fill up column values from schema
* [#1148](https://github.com/robmorgan/phinx/pull/1148) When execute command `seed:run`, insert all data to a table in a bulk
* Bug fixes
* [#1111](https://github.com/cakephp/phinx/pull/1111) Fixed error when calling truncateTable() method
* [#1117](https://github.com/cakephp/phinx/pull/1117) Quote column names in the addIndex() method for PostgresSQL
* [#1126](https://github.com/robmorgan/phinx/pull/1126) Fix invalid changeColumn regex causing deletions
* [#1093](https://github.com/robmorgan/phinx/pull/1093) Fix issue with dropColumn command in SQLite
* [#1091](https://github.com/robmorgan/phinx/pull/1091) Fix pgsql quoting in comment clause
* [#1094](https://github.com/robmorgan/phinx/pull/1094) Fix varchar to datetime error
**0.8.1** (Monday, 5th June 2017)
* Documentation updates
* Pull requests
* [#768](https://github.com/robmorgan/phinx/pull/768) Support for MySQL unsigned primary keys
* [#1104](https://github.com/robmorgan/phinx/pull/1029) Removed support for HHVM
* [#1082](https://github.com/robmorgan/phinx/pull/1082) Fixed paths displayed in text output
* [#1055](https://github.com/robmorgan/phinx/pull/1055) Text wrapper improvements
* [#1056](https://github.com/robmorgan/phinx/pull/1056) Update Input/OutputInterface on cached Manager
* Bug fixes
* [#1060](https://github.com/robmorgan/phinx/pull/1060) Fixed rollback on only one migration
**0.8.0** (Tuesday, 28th February 2017)
* Documentation updates
* New features
* [#1045](https://github.com/robmorgan/phinx/pull/1045) Rollbacks by start time - Thanks to [Daniel Gomes](https://github.com/daniel-gomes-sociomantic).
Please see [UPGRAGE_0.8](https://github.com/robmorgan/phinx/blob/master/UPGRADE_0.8.md) for additional details regarding [#1045](https://github.com/robmorgan/phinx/pull/1045)
**0.7.2** (Tuesday, 28th February 2017)
* Bug fixes
* [#1041](https://github.com/robmorgan/phinx/pull/1041) Quote new column name in renameColumn in PostgresAdapter
* [#1048](https://github.com/robmorgan/phinx/pull/1048) Do not allow the start_time to be updated when setting a breakpoint
**0.7.1** (Sunday, 19th February 2017)
* Documentation updates
* New features
* [#978](https://github.com/robmorgan/phinx/pull/978) Add table truncate method
* Pull requests
* [#1029](https://github.com/robmorgan/phinx/pull/1029) Add vendor to Phinx path to align with other docs
**0.7.0** (Friday, 10th February 2017)
* Documentation updates
* New features
* [#885](https://github.com/robmorgan/phinx/pull/885) Add `collation` and `encoding` options for MySQL text and char columns
* Pull requests
* [#813](https://github.com/robmorgan/phinx/pull/813) Fix SQLite data insertion
* [#867](https://github.com/robmorgan/phinx/pull/867) Improve Postgres geography types creation
* [#966](https://github.com/robmorgan/phinx/pull/966) Remove unused variable
* [#973](https://github.com/robmorgan/phinx/pull/973) Improve documentation grammar
* [#979](https://github.com/robmorgan/phinx/pull/979) Add `.gitattributes` to exclude tests on Composer export
* [#983](https://github.com/robmorgan/phinx/pull/983) Document changing a foreign key constraint name
* [#1001](https://github.com/robmorgan/phinx/pull/1001) Cleanup phpunit mock warnings
* [#1007](https://github.com/robmorgan/phinx/pull/1007) Integrate PHPStan and fix issues discovered
* [#1020](https://github.com/robmorgan/phinx/pull/1020) Document adding named foreign keys
* [#1028](https://github.com/robmorgan/phinx/pull/1028) Add docs about MySQL table specific options
* [#1033](https://github.com/robmorgan/phinx/pull/1033) Add PHP 7.1 to Travis CI
**0.6.6** (Monday, 23rd January 2017)
* Documentation updates
* New Features
* [#943](https://github.com/robmorgan/phinx/pull/943) Adding hint on migration name in CamelCase
* Bug fixes
* [#813](https://github.com/robmorgan/phinx/pull/813) fix(pdo_sqlite): Correctly handles data insertions
* [#956](https://github.com/robmorgan/phinx/pull/956) Fix seed command accepting string
* [#1002](https://github.com/robmorgan/phinx/pull/1002) Fix Appveyor builds
* [#1006](https://github.com/robmorgan/phinx/pull/1006) Fix update column with , in definition (SQLite)
* Development branch changed to `master`
**0.6.5** (Thursday, 27th October 2016)
* Documentation updates
* Pull requests
* [#831](https://github.com/robmorgan/phinx/pull/831) Typos
* [#929](https://github.com/robmorgan/phinx/pull/929) Support glob brace for seed paths
* [#949](https://github.com/robmorgan/phinx/pull/949) Fix for Config::getMigrationBaseClassName
* [#958](https://github.com/robmorgan/phinx/pull/958) Allow console input to be used within adapters
**0.6.4** (Wednesday, 27th July 2016)
* Documentation updates
* Pull requests
* [#909](https://github.com/robmorgan/phinx/pull/909) Declare test class properties
* [#910](https://github.com/robmorgan/phinx/pull/910), [#916](https://github.com/robmorgan/phinx/pull/916) Remove unused variables
* [#912](https://github.com/robmorgan/phinx/pull/912) ConfigInterface usage consistency
* [#914](https://github.com/robmorgan/phinx/pull/914) Set return values and @return documentation
* [#918](https://github.com/robmorgan/phinx/pull/918) Docblock correction for Phinx\Migration\Manager::executeSeed()
* [#921](https://github.com/robmorgan/phinx/pull/921) Add Phinx\Wrapper\TextWrapper::getSeed()
* Bug fixes
* [#908](https://github.com/robmorgan/phinx/pull/908) Fix setting options for Column, ForeignKey and Index
* [#922](https://github.com/robmorgan/phinx/pull/922) SQLite adapter drops table on changeColumn if there's a foreign key
**0.6.3** (Monday, 18th July 2016)
* New features
* [#707](https://github.com/robmorgan/phinx/pull/707/files) Add arguments for timestamps columns names
* Documentation cleanup
* Bug fixes
* [#884](https://github.com/robmorgan/phinx/pull/884) Only rollback 1 migration when only 2 migrations exist
* Input and Output are now correctly supplied to migration template creation classes
**0.6.2** (Thursday, 23rd June 2016)
* Fix breakpoint support for Postgres
* HHVM now passes all tests
**0.6.1** (Tuesday, 21st June 2016)
* Fix rollback when only 1 migration
**0.6.0** (Tuesday, 21st June 2016)
* Backward incompatibility - see [UPGRADE_0.6](UPGRADE_0.6.md) document
* Introduce Input and Output access to migrations and template creation
* New breakpoint command
* Moved version history to this CHANGELOG.md document
* More tests
**0.5.5** (Friday, 17th May 2016)
* Fix support for running multiple seeders
* Bug fix for migration template source - defaults and command line
* Bug fixes
**0.5.4** (Monday, 25th April 2016)
* Added support for running multiple seeders
* Use `GLOB_BRACE` when finding migrations only if its available
* Added support for MySQL `VARBINARY` column type
* Minor bug fixes
**0.5.3** (Monday, 7th March 2016)
* Critical fix: allow `migration_name` to be `null`. Introduced in 0.5.2
* Status command now shows migration start and end times
* Bug fix for rolling back by date
* Documentation improvements
**0.5.2** (Tuesday, 1st March 2016)
* Status command now includes missing migration names
* Added support for Postgres table comments
* Added `insert()` for the TablePrefixAdapter
* Fixed the migration verbosity flag
* Added MySQL 5.7 JSON support
* Added support for MySQL `FULLTEXT` indexes
* Postgres now supports `BIGSERIAL` for primary keys
* Added support for MySQL index limits
* Initial support for multiple migration paths (using glob)
* Documentation improvements
* Unit test enhancements
**0.5.1** (Wednesday, 30th December 2015)
* **PHP 5.3 is no longer supported!**
* Add support for Symfony 3.0 components
* Ensure that the `status` command returns the correct exit code
* Allow `$version` to be passed into templates
* Support for MySQL `YEAR` column type
* Multiple documentation updates and corrections
**0.5.0** (Monday, 30th November 2015)
* Support for seeding data after database creation
* The migration and seed directories are now nested under `db` by default
* Moved `Phinx\Migration\Util` to `Phinx\Util\Util`
* All `insert()` methods now have a slightly different method signature
* Fixed key/insert operations for MySQL
* Introduced `AdapterInterface::hasIndexByName()`
* Improved `dropForeignKey()` handling for SQLite
* Added support for the MySQL `binary` datatype. BLOBs now use the proper type.
* The status command shows a count of pending migrations in JSON output
* We are now testing against PHP 7
**0.4.6** (Friday, 11th September 2015)
* You can now set custom migration templates in the config files
* Support for MySQL unsigned booleans
* Support for Postgres `smallint` column types
* Support for `AFTER` when using `changeColumn()` with MySQL
* Support for `precision` and `scale` when using the Postgres `decimal` type
* Fixed a bug where duplicate migration names could be used
* The schema table is now created with a primary key
* Fixed issues when using the MySQL `STRICT_TRANS_TABLE` mode
* Improved the docs in the default migration template
* Made Box PHAR ignore the bundled `phinx.yml` configuration file
* Updated Box installer URL
* Internal code improvements
* Documentation improvements
**0.4.5** (Tuesday, 1st September 2015)
* The rollback command now supports a date argument
* Fixed DBLIB DSN strings for Microsoft SQL Server
* Postgres support for `jsonb` columns added
* The `addTimestamps()` helper method no longer updates the `created_at` column
* Fix for Postgres named foreign keys
* Unit test improvements (including strict warnings)
* Documentation improvements
**0.4.4** (Sunday, 14th June 2015)
* The `change` method is now the default
* Added a generic adapter insert method. Warning: The implementation will change!
* Updated Symfony depdencies to ~2.7
* Support for MySQL `BLOB` column types
* SQLite migration fixes
* Documentation improvements
**0.4.3** (Monday, 23rd February 2015)
* Postgres bugfix for modifying column DEFAULTs
* MySQL bugfix for setting column INTEGER lengths
* SQLite bugfix for creating multiple indexes with similar names
**0.4.2.1** (Saturday, 7th February 2015)
* Proper release, updated docs
**0.4.2** (Friday, 6th February 2015)
* Postgres support for `json` columns added
* MySQL support for `enum` and `set` columns added
* Allow setting `identity` option on columns
* Template configuration and generation made more extensible
* Created a base class for `ProxyAdapter` and `TablePrefixAdapter`
* Switched to PSR-4
**0.4.1** (Tuesday, 23rd December 2014)
* MySQL support for reserved words in hasColumn and getColumns methods
* Better MySQL Adapter test coverage and performance fixes
* Updated dependent Symfony components to 2.6.x
**0.4.0** (Sunday, 14th December 2014)
* Adding initial support for running Phinx via a web interface
* Support for table prefixes and suffixes
* Bugfix for foreign key options
* MySQL keeps column default when renaming columns
* MySQL support for tiny/medium and longtext columns added
* Changed SQL Server binary columns to varbinary
* MySQL supports table comments
* Postgres supports column comments
* Empty strings are now supported for default column values
* Booleans are now supported for default column values
* Fixed SQL Server default constraint error when changing column types
* Migration timestamps are now created in UTC
* Locked Symfony Components to 2.5.0
* Support for custom migration base classes
* Cleaned up source code formatting
* Migrations have access to the output stream
* Support for custom PDO connections when a PHP config
* Added support for Postgres UUID type
* Fixed issue with Postgres dropping foreign keys
**0.3.8** (Sunday, 5th October 2014)
* Added new CHAR & Geospatial column types
* Added MySQL unix socket support
* Added precision & scale support for SQL Server
* Several bug fixes for SQLite
* Improved error messages
* Overall code optimizations
* Optimizations to MySQL hasTable method
**0.3.7** (Tuesday, 12th August 2014)
* Smarter configuration file support
* Support for Postgres Schemas
* Fixed charset support for Microsoft SQL Server
* Fix for Unique indexes in all adapters
* Improvements for MySQL foreign key migration syntax
* Allow MySQL column types with extra info
* Fixed SQLite autoincrement behaviour
* PHPDoc improvements
* Documentation improvements
* Unit test improvements
* Removing primary_key as a type
**0.3.6** (Sunday, 29th June 2014)
* Add custom adapter support
* Fix PHP 5.3 compatibility for SQL Server
**0.3.5** (Saturday, 21st June 2014)
* Added Microsoft SQL Server support
* Removed Primary Key column type
* Cleaned up and optimized many methods
* Updated Symfony dependencies to v2.5.0
* PHPDoc improvements
**0.3.4** (Sunday, 27th April 2014)
* Added support MySQL unsigned integer, biginteger, float and decimal types
* Added JSON output support for the status command
* Fix a bug where Postgres couldnt rollback foreign keys
* Moved Phinx type references to interface constants
* Fixed a bug with SQLite in-memory databases
**0.3.3** (Saturday, 22nd March 2014)
* Added support for JSON configuration
* Named index support for all adapters (thanks @archer308)
* Updated Composer dependencies
* Fix for SQLite Integer Type
* Fix for MySQL port option
**0.3.2** (Monday, 24th February 2014)
* Adding better Postgres type support
**0.3.1** (Sunday, 23rd February 2014)
* Adding MySQL charset support to the YAML config
* Removing trailing spaces
**0.3.0** (Sunday, 2nd February 2014)
* PSR-2 support
* Method to add timestamps easily to tables
* Support for column comments in the Postgres adapter
* Fixes for MySQL driver options
* Fixes for MySQL biginteger type
**0.2.9** (Saturday, 16th November 2013)
* Added SQLite Support
* Improving the unit tests, especially on Windows
**0.2.8** (Sunday, 25th August 2013)
* Added PostgresSQL Support
**0.2.7** (Saturday, 24th August 2013)
* Critical fix for a token parsing bug
* Removed legacy build system
* Improving docs
**0.2.6** (Saturday, 24th August 2013)
* Added support for environment vars in config files
* Added support for environment vars to set the Phinx Env
* Improving docs
* Fixed a bug with column names in indexes
* Changes for developers in regards to the unit tests
**0.2.5** (Sunday, 26th May 2013)
* Added support for Box Phar Archive Packaging
* Added support for MYSQL_ATTR driver options
* Fixed a bug where foreign keys cannot be removed
* Added support for MySQL table collation
* Updated Composer dependencies
* Removed verbosity options, now relies on Symfony instead
* Improved unit tests
**0.2.4** (Saturday, 20th April 2013)
* The Rollback command supports the verbosity parameter
* The Rollback command has more detailed output
* Table::dropForeignKey now returns the table instance
**0.2.3** (Saturday, 6th April 2013)
* Fixed a reporting bug when Phinx couldn't connect to a database
* Added support for the MySQL 'ON UPDATE' function
* Phinx timestamp is now mapped to MySQL timestamp instead of datetime
* Fixed a docs typo for the minimum PHP version
* Added UTF8 support for migrations
* Changed regex to handle migration names differently
* Added support for custom MySQL table engines such as MyISAM
* Added the change method to the migration template
**0.2.2** (Sunday, 3rd March 2013)
* Added a new verbosity parameter to see more output when migrating
* Support for PHP config files
**0.2.1** (Sunday, 3rd March 2013)
* Broken Release. Do not use!
* Unit tests no longer rely on the default phinx.yml file
* Running migrate for the first time does not give php warnings
* `default_migration_table` is now actually supported
* Updated docblocks to 2013.
**0.2.0** (Sunday, 13th January 2013)
* First Birthday Release
* Added Reversible Migrations
* Removed options parameter from AdapterInterface::hasColumn()
**0.1.7** (Tuesday, 8th January 2013)
* Improved documentation on the YAML configuration file
* Removed options parameter from AdapterInterface::dropIndex()
**0.1.6** (Sunday, 9th December 2012)
* Added foreign key support
* Removed PEAR support
* Support for auto_increment on custom id columns
* Bugfix for column default value 0
* Documentation improvements
**0.1.5** (Sunday, 4th November 2012)
* Added a test command
* Added transactions for adapters that support it
* Changing the Table API to use pending column methods
* Fixed a bug when defining multiple indexes on a table
**0.1.4** (Sunday, 21st October 2012)
* Documentation Improvements
**0.1.3** (Saturday, 20th October 2012)
* Fixed broken composer support
**0.1.2** (Saturday, 20th October 2012)
* Added composer support
* Now forces migrations to be in CamelCase format
* Now specifies the database name when migrating
* Creates the internal log table using its API instead of raw SQL
**0.1.1** (Wednesday, 13th June 2012)
* First point release. Ready for limited production use.
**0.1.0** (Friday, 13th January 2012)
* Initial public release.
phinx-0.9.2/LICENSE 0000664 0000000 0000000 00000002066 13217376123 0013666 0 ustar 00root root 0000000 0000000 (The MIT license)
Copyright (c) 2012-2017 Rob Morgan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
phinx-0.9.2/README.md 0000664 0000000 0000000 00000010626 13217376123 0014141 0 ustar 00root root 0000000 0000000 # [Phinx](https://phinx.org): Simple PHP Database Migrations
[](https://travis-ci.org/cakephp/phinx)
[](https://ci.appveyor.com/project/robmorgan/phinx)
[](https://codecov.io/gh/cakephp/phinx)
[](https://packagist.org/packages/robmorgan/phinx)
[](https://packagist.org/packages/robmorgan/phinx)
[](https://gitter.im/phinx-php/Lobby)
## Intro
Phinx makes it ridiculously easy to manage the database migrations for your PHP app. In less than 5 minutes, you can install Phinx and create your first database migration. Phinx is just about migrations without all the bloat of a database ORM system or framework.
**Check out https://book.cakephp.org/3.0/en/phinx.html ([EN](https://book.cakephp.org/3.0/en/phinx.html), [ZH](https://tsy12321.gitbooks.io/phinx-doc/)) for the comprehensive documentation.**

### Features
* Write database migrations using database agnostic PHP code.
* Migrate up and down.
* Migrate on deployment.
* Seed data after database creation.
* Get going in less than 5 minutes.
* Stop worrying about the state of your database.
* Take advantage of SCM features such as branching.
* Integrate with any app.
### Supported Adapters
Phinx natively supports the following database adapters:
* MySQL
* PostgreSQL
* SQLite
* Microsoft SQL Server
## Install & Run
### Composer
The fastest way to install Phinx is to add it to your project using Composer (http://getcomposer.org/).
1. Install Composer:
```
curl -sS https://getcomposer.org/installer | php
```
1. Require Phinx as a dependency using Composer:
```
php composer.phar require robmorgan/phinx
```
1. Install Phinx:
```
php composer.phar install
```
1. Execute Phinx:
```
php vendor/bin/phinx
```
### As a Phar
You can also use the Box application to build Phinx as a Phar archive (https://box-project.github.io/box2/).
1. Clone Phinx from GitHub
```
git clone https://github.com/cakephp/phinx.git
cd phinx
```
1. Install Composer
```
curl -s https://getcomposer.org/installer | php
```
1. Install the Phinx dependencies
```
php composer.phar install
```
1. Install Box:
```
curl -LSs https://box-project.github.io/box2/installer.php | php
```
1. Create a Phar archive
```
php box.phar build
```
## Documentation
Check out https://book.cakephp.org/3.0/en/phinx.html for the comprehensive documentation.
Other translations include:
* [Chinese](https://tsy12321.gitbooks.io/phinx-doc/) (Maintained by [@tsy12321](https://github.com/tsy12321/phinx-doc))
## Contributing
Please read the [CONTRIBUTING](CONTRIBUTING.md) document.
## News & Updates
Follow [@CakePHP](https://twitter.com/cakephp) on Twitter to stay up to date.
## Misc
### Version History
Please read the [CHANGELOG](CHANGELOG.md) document.
### License
(The MIT license)
Copyright (c) 2017 Rob Morgan
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
phinx-0.9.2/UPGRADE_0.6.md 0000664 0000000 0000000 00000000501 13217376123 0014645 0 ustar 00root root 0000000 0000000 # Upgrading Phinx to 0.6
* Phinx 0.6 allows template creation access to the InputInterface and OutputInterface.
To upgrade, rather than implementing the ```\Phinx\Migration\CreationInterface``` interface in your
template creation class, extend the ```\Phinx\Migration\AbstractTemplateCreation``` abstract class.
phinx-0.9.2/UPGRADE_0.8.md 0000664 0000000 0000000 00000001645 13217376123 0014661 0 ustar 00root root 0000000 0000000 # Upgrading Phinx to 0.8
* Phinx 0.8 allows for `phinx rollback` and `phinx status` to operate on migrations in reverse execution order,
rather than reverse creation order. To achieve this new ordering, you will need to add a new entry in your
`phinx.yml` file (or equivalent).
The setting is called `version_order` and supports 2 values:
* `creation` - this is the default value and matches the standard behaviour of executing rollbacks in the
reverse order based upon the creation datetime (also known as `version`).
* `execution` - this is the new value and will execute rollbacks in the reverse order in which they were
applied.
This feature will be of most importance when development of migrations takes place in different branches
within a codebase and are merged in to master for deployment. It will no longer matter when the migrations
were created if it becomes necessary to rollback the migrations.
phinx-0.9.2/app/ 0000775 0000000 0000000 00000000000 13217376123 0013435 5 ustar 00root root 0000000 0000000 phinx-0.9.2/app/phinx.php 0000664 0000000 0000000 00000002761 13217376123 0015302 0 ustar 00root root 0000000 0000000 'getStatus',
'migrate' => 'getMigrate',
'rollback' => 'getRollback',
];
// Extract the requested command from the URL, default to "status".
$command = trim(parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH), '/');
if (!$command) {
$command = 'status';
}
// Verify that the command exists, or list available commands.
if (!isset($routes[$command])) {
$commands = implode(', ', array_keys($routes));
header('Content-Type: text/plain', true, 404);
die("Command not found! Valid commands are: {$commands}.");
}
// Get the environment and target version parameters.
$env = isset($_GET['e']) ? $_GET['e'] : null;
$target = isset($_GET['t']) ? $_GET['t'] : null;
// Check if debugging is enabled.
$debug = !empty($_GET['debug']) && filter_var($_GET['debug'], FILTER_VALIDATE_BOOLEAN);
// Execute the command and determine if it was successful.
$output = call_user_func([$wrap, $routes[$command]], $env, $target);
$error = $wrap->getExitCode() > 0;
// Finally, display the output of the command.
header('Content-Type: text/plain', true, $error ? 500 : 200);
if ($debug) {
// Show what command was executed based on request parameters.
$args = implode(', ', [var_export($env, true), var_export($target, true)]);
echo "DEBUG: $command($args)" . PHP_EOL . PHP_EOL;
}
echo $output;
phinx-0.9.2/bin/ 0000775 0000000 0000000 00000000000 13217376123 0013425 5 ustar 00root root 0000000 0000000 phinx-0.9.2/bin/phinx 0000775 0000000 0000000 00000002320 13217376123 0014476 0 ustar 00root root 0000000 0000000 #!/usr/bin/env php
run();
phinx-0.9.2/bin/phinx.bat 0000664 0000000 0000000 00000001600 13217376123 0015240 0 ustar 00root root 0000000 0000000 @echo off
rem This script will do the following:
rem - check for PHP_COMMAND env, if found, use it.
rem - if not found detect php, if found use it, otherwise err and terminate
if "%OS%"=="Windows_NT" @setlocal
rem %~dp0 is expanded pathname of the current script under NT
set DEFAULT_PHINX_HOME=%~dp0..
goto init
goto cleanup
:init
if "%PHINX_HOME%" == "" set PHINX_HOME=%DEFAULT_PHINX_HOME%
set DEFAULT_PHINX_HOME=
if "%PHP_COMMAND%" == "" goto no_phpcommand
goto run
goto cleanup
:run
"%PHP_COMMAND%" -d html_errors=off -qC "%PHINX_HOME%\bin\phinx" %*
goto cleanup
:no_phpcommand
rem PHP_COMMAND environment variable not found, assuming php.exe is on path.
set PHP_COMMAND=php.exe
goto init
:err_home
echo ERROR: Environment var PHINX_HOME not set. Please point this
echo variable to your local phinx installation!
goto cleanup
:cleanup
if "%OS%"=="Windows_NT" @endlocal
rem pause phinx-0.9.2/composer.json 0000664 0000000 0000000 00000003353 13217376123 0015403 0 ustar 00root root 0000000 0000000 {
"name": "robmorgan/phinx",
"type": "library",
"description": "Phinx makes it ridiculously easy to manage the database migrations for your PHP app.",
"keywords": ["phinx", "migrations", "database", "db", "database migrations"],
"homepage": "https://phinx.org",
"license": "MIT",
"version": "0.9.2",
"authors": [{
"name": "Rob Morgan",
"email": "robbym@gmail.com",
"homepage": "https://robmorgan.id.au",
"role": "Lead Developer"
}, {
"name": "Woody Gilk",
"email": "woody.gilk@gmail.com",
"homepage": "http://shadowhand.me",
"role": "Developer"
}, {
"name": "Richard Quadling",
"email": "rquadling@gmail.com",
"role": "Developer"
}, {
"name": "CakePHP Community",
"homepage": "https://github.com/cakephp/phinx/graphs/contributors"
}],
"require": {
"php": ">=5.4",
"symfony/console": "^2.8|^3.0|^4.0",
"symfony/config": "^2.8|^3.0|^4.0",
"symfony/yaml": "^2.8|^3.0|^4.0"
},
"require-dev": {
"phpunit/phpunit": "^4.8.35|^5.7|^6.5",
"cakephp/cakephp-codesniffer": "^3.0"
},
"autoload": {
"psr-4": {
"Phinx\\": "src/Phinx"
}
},
"autoload-dev": {
"psr-4": {
"Test\\Phinx\\": "tests/Phinx"
}
},
"scripts": {
"check": [
"@test",
"@cs-check"
],
"cs-check": "phpcs --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests ./app",
"cs-fix": "phpcbf --colors --standard=vendor/cakephp/cakephp-codesniffer/CakePHP ./src ./tests ./app",
"test": "phpunit --colors=always"
},
"bin": ["bin/phinx"]
}
phinx-0.9.2/phinx.yml 0000664 0000000 0000000 00000001315 13217376123 0014526 0 ustar 00root root 0000000 0000000 paths:
migrations: '%%PHINX_CONFIG_DIR%%/db/migrations'
seeds: '%%PHINX_CONFIG_DIR%%/db/seeds'
environments:
default_migration_table: phinxlog
default_database: development
production:
adapter: mysql
host: localhost
name: production_db
user: root
pass: ''
port: 3306
charset: utf8
development:
adapter: mysql
host: localhost
name: development_db
user: root
pass: ''
port: 3306
charset: utf8
testing:
adapter: mysql
host: localhost
name: testing_db
user: root
pass: ''
port: 3306
charset: utf8
version_order: creation
phinx-0.9.2/src/ 0000775 0000000 0000000 00000000000 13217376123 0013444 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/ 0000775 0000000 0000000 00000000000 13217376123 0014532 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Config/ 0000775 0000000 0000000 00000000000 13217376123 0015737 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Config/Config.php 0000664 0000000 0000000 00000027142 13217376123 0017663 0 ustar 00root root 0000000 0000000 configFilePath = $configFilePath;
$this->values = $this->replaceTokens($configArray);
}
/**
* Create a new instance of the config class using a Yaml file path.
*
* @param string $configFilePath Path to the Yaml File
* @throws \RuntimeException
* @return \Phinx\Config\Config
*/
public static function fromYaml($configFilePath)
{
$configFile = file_get_contents($configFilePath);
$configArray = Yaml::parse($configFile);
if (!is_array($configArray)) {
throw new \RuntimeException(sprintf(
'File \'%s\' must be valid YAML',
$configFilePath
));
}
return new static($configArray, $configFilePath);
}
/**
* Create a new instance of the config class using a JSON file path.
*
* @param string $configFilePath Path to the JSON File
* @throws \RuntimeException
* @return \Phinx\Config\Config
*/
public static function fromJson($configFilePath)
{
$configArray = json_decode(file_get_contents($configFilePath), true);
if (!is_array($configArray)) {
throw new \RuntimeException(sprintf(
'File \'%s\' must be valid JSON',
$configFilePath
));
}
return new static($configArray, $configFilePath);
}
/**
* Create a new instance of the config class using a PHP file path.
*
* @param string $configFilePath Path to the PHP File
* @throws \RuntimeException
* @return \Phinx\Config\Config
*/
public static function fromPhp($configFilePath)
{
ob_start();
/** @noinspection PhpIncludeInspection */
$configArray = include($configFilePath);
// Hide console output
ob_end_clean();
if (!is_array($configArray)) {
throw new \RuntimeException(sprintf(
'PHP file \'%s\' must return an array',
$configFilePath
));
}
return new static($configArray, $configFilePath);
}
/**
* {@inheritdoc}
*/
public function getEnvironments()
{
if (isset($this->values) && isset($this->values['environments'])) {
$environments = [];
foreach ($this->values['environments'] as $key => $value) {
if (is_array($value)) {
$environments[$key] = $value;
}
}
return $environments;
}
return null;
}
/**
* {@inheritdoc}
*/
public function getEnvironment($name)
{
$environments = $this->getEnvironments();
if (isset($environments[$name])) {
if (isset($this->values['environments']['default_migration_table'])) {
$environments[$name]['default_migration_table'] =
$this->values['environments']['default_migration_table'];
}
return $environments[$name];
}
return null;
}
/**
* {@inheritdoc}
*/
public function hasEnvironment($name)
{
return ($this->getEnvironment($name) !== null);
}
/**
* {@inheritdoc}
*/
public function getDefaultEnvironment()
{
// The $PHINX_ENVIRONMENT variable overrides all other default settings
$env = getenv('PHINX_ENVIRONMENT');
if (!empty($env)) {
if ($this->hasEnvironment($env)) {
return $env;
}
throw new \RuntimeException(sprintf(
'The environment configuration (read from $PHINX_ENVIRONMENT) for \'%s\' is missing',
$env
));
}
// if the user has configured a default database then use it,
// providing it actually exists!
if (isset($this->values['environments']['default_database'])) {
if ($this->getEnvironment($this->values['environments']['default_database'])) {
return $this->values['environments']['default_database'];
}
throw new \RuntimeException(sprintf(
'The environment configuration for \'%s\' is missing',
$this->values['environments']['default_database']
));
}
// else default to the first available one
if (is_array($this->getEnvironments()) && count($this->getEnvironments()) > 0) {
$names = array_keys($this->getEnvironments());
return $names[0];
}
throw new \RuntimeException('Could not find a default environment');
}
/**
* {@inheritdoc}
*/
public function getAlias($alias)
{
return !empty($this->values['aliases'][$alias]) ? $this->values['aliases'][$alias] : null;
}
/**
* {@inheritdoc}
*/
public function getConfigFilePath()
{
return $this->configFilePath;
}
/**
* {@inheritdoc}
*/
public function getMigrationPaths()
{
if (!isset($this->values['paths']['migrations'])) {
throw new \UnexpectedValueException('Migrations path missing from config file');
}
if (is_string($this->values['paths']['migrations'])) {
$this->values['paths']['migrations'] = [$this->values['paths']['migrations']];
}
return $this->values['paths']['migrations'];
}
/**
* Gets the base class name for migrations.
*
* @param bool $dropNamespace Return the base migration class name without the namespace.
* @return string
*/
public function getMigrationBaseClassName($dropNamespace = true)
{
$className = !isset($this->values['migration_base_class']) ? 'Phinx\Migration\AbstractMigration' : $this->values['migration_base_class'];
return $dropNamespace ? substr(strrchr($className, '\\'), 1) ?: $className : $className;
}
/**
* {@inheritdoc}
*/
public function getSeedPaths()
{
if (!isset($this->values['paths']['seeds'])) {
throw new \UnexpectedValueException('Seeds path missing from config file');
}
if (is_string($this->values['paths']['seeds'])) {
$this->values['paths']['seeds'] = [$this->values['paths']['seeds']];
}
return $this->values['paths']['seeds'];
}
/**
* Get the template file name.
*
* @return string|false
*/
public function getTemplateFile()
{
if (!isset($this->values['templates']['file'])) {
return false;
}
return $this->values['templates']['file'];
}
/**
* Get the template class name.
*
* @return string|false
*/
public function getTemplateClass()
{
if (!isset($this->values['templates']['class'])) {
return false;
}
return $this->values['templates']['class'];
}
/**
* Get the version order.
*
* @return string
*/
public function getVersionOrder()
{
if (!isset($this->values['version_order'])) {
return self::VERSION_ORDER_CREATION_TIME;
}
return $this->values['version_order'];
}
/**
* Is version order creation time?
*
* @return bool
*/
public function isVersionOrderCreationTime()
{
$versionOrder = $this->getVersionOrder();
return $versionOrder == self::VERSION_ORDER_CREATION_TIME;
}
/**
* Replace tokens in the specified array.
*
* @param array $arr Array to replace
* @return array
*/
protected function replaceTokens(array $arr)
{
// Get environment variables
// $_ENV is empty because variables_order does not include it normally
$tokens = [];
foreach ($_SERVER as $varname => $varvalue) {
if (0 === strpos($varname, 'PHINX_')) {
$tokens['%%' . $varname . '%%'] = $varvalue;
}
}
// Phinx defined tokens (override env tokens)
$tokens['%%PHINX_CONFIG_PATH%%'] = $this->getConfigFilePath();
$tokens['%%PHINX_CONFIG_DIR%%'] = dirname($this->getConfigFilePath());
// Recurse the array and replace tokens
return $this->recurseArrayForTokens($arr, $tokens);
}
/**
* Recurse an array for the specified tokens and replace them.
*
* @param array $arr Array to recurse
* @param array $tokens Array of tokens to search for
* @return array
*/
protected function recurseArrayForTokens($arr, $tokens)
{
$out = [];
foreach ($arr as $name => $value) {
if (is_array($value)) {
$out[$name] = $this->recurseArrayForTokens($value, $tokens);
continue;
}
if (is_string($value)) {
foreach ($tokens as $token => $tval) {
$value = str_replace($token, $tval, $value);
}
$out[$name] = $value;
continue;
}
$out[$name] = $value;
}
return $out;
}
/**
* {@inheritdoc}
*/
public function offsetSet($id, $value)
{
$this->values[$id] = $value;
}
/**
* {@inheritdoc}
*/
public function offsetGet($id)
{
if (!array_key_exists($id, $this->values)) {
throw new \InvalidArgumentException(sprintf('Identifier "%s" is not defined.', $id));
}
return $this->values[$id] instanceof \Closure ? $this->values[$id]($this) : $this->values[$id];
}
/**
* {@inheritdoc}
*/
public function offsetExists($id)
{
return isset($this->values[$id]);
}
/**
* {@inheritdoc}
*/
public function offsetUnset($id)
{
unset($this->values[$id]);
}
}
phinx-0.9.2/src/Phinx/Config/ConfigInterface.php 0000664 0000000 0000000 00000006764 13217376123 0021513 0 ustar 00root root 0000000 0000000 null if no environments exist.
*
* @return array|null
*/
public function getEnvironments();
/**
* Returns the configuration for a given environment.
*
* This method returns null
if the specified environment
* doesn't exist.
*
* @param string $name
* @return array|null
*/
public function getEnvironment($name);
/**
* Does the specified environment exist in the configuration file?
*
* @param string $name Environment Name
* @return bool
*/
public function hasEnvironment($name);
/**
* Gets the default environment name.
*
* @throws \RuntimeException
* @return string
*/
public function getDefaultEnvironment();
/**
* Get the aliased value from a supplied alias.
*
* @param string $alias
*
* @return string|null
*/
public function getAlias($alias);
/**
* Gets the config file path.
*
* @return string
*/
public function getConfigFilePath();
/**
* Gets the paths to search for migration files.
*
* @return string[]
*/
public function getMigrationPaths();
/**
* Gets the paths to search for seed files.
*
* @return string[]
*/
public function getSeedPaths();
/**
* Get the template file name.
*
* @return string|false
*/
public function getTemplateFile();
/**
* Get the template class name.
*
* @return string|false
*/
public function getTemplateClass();
/**
* Get the version order.
*
* @return string
*/
public function getVersionOrder();
/**
* Is version order creation time?
*
* @return bool
*/
public function isVersionOrderCreationTime();
/**
* Gets the base class name for migrations.
*
* @param bool $dropNamespace Return the base migration class name without the namespace.
* @return string
*/
public function getMigrationBaseClassName($dropNamespace = true);
}
phinx-0.9.2/src/Phinx/Config/NamespaceAwareInterface.php 0000664 0000000 0000000 00000003314 13217376123 0023146 0 ustar 00root root 0000000 0000000 getMigrationPaths();
return $this->searchNamespace($path, $paths);
}
/**
* Get Seed Namespace associated with path.
*
* @param string $path
* @return string|null
*/
public function getSeedNamespaceByPath($path)
{
$paths = $this->getSeedPaths();
return $this->searchNamespace($path, $paths);
}
}
phinx-0.9.2/src/Phinx/Console/ 0000775 0000000 0000000 00000000000 13217376123 0016134 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Console/Command/ 0000775 0000000 0000000 00000000000 13217376123 0017512 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Console/Command/AbstractCommand.php 0000664 0000000 0000000 00000024362 13217376123 0023274 0 ustar 00root root 0000000 0000000
*/
abstract class AbstractCommand extends Command
{
/**
* The location of the default migration template.
*/
const DEFAULT_MIGRATION_TEMPLATE = '/../../Migration/Migration.template.php.dist';
/**
* The location of the default seed template.
*/
const DEFAULT_SEED_TEMPLATE = '/../../Seed/Seed.template.php.dist';
/**
* @var \Phinx\Config\ConfigInterface
*/
protected $config;
/**
* @var \Phinx\Db\Adapter\AdapterInterface
*/
protected $adapter;
/**
* @var \Phinx\Migration\Manager
*/
protected $manager;
/**
* {@inheritdoc}
*/
protected function configure()
{
$this->addOption('--configuration', '-c', InputOption::VALUE_REQUIRED, 'The configuration file to load');
$this->addOption('--parser', '-p', InputOption::VALUE_REQUIRED, 'Parser used to read the config file. Defaults to YAML');
}
/**
* Bootstrap Phinx.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
public function bootstrap(InputInterface $input, OutputInterface $output)
{
if (!$this->getConfig()) {
$this->loadConfig($input, $output);
}
$this->loadManager($input, $output);
// report the paths
$paths = $this->getConfig()->getMigrationPaths();
$output->writeln('using migration paths ');
foreach (Util::globAll($paths) as $path) {
$output->writeln(' - ' . realpath($path) . '');
}
try {
$paths = $this->getConfig()->getSeedPaths();
$output->writeln('using seed paths ');
foreach (Util::globAll($paths) as $path) {
$output->writeln(' - ' . realpath($path) . '');
}
} catch (\UnexpectedValueException $e) {
// do nothing as seeds are optional
}
}
/**
* Sets the config.
*
* @param \Phinx\Config\ConfigInterface $config
* @return \Phinx\Console\Command\AbstractCommand
*/
public function setConfig(ConfigInterface $config)
{
$this->config = $config;
return $this;
}
/**
* Gets the config.
*
* @return \Phinx\Config\ConfigInterface
*/
public function getConfig()
{
return $this->config;
}
/**
* Sets the database adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter
* @return \Phinx\Console\Command\AbstractCommand
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* Gets the database adapter.
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* Sets the migration manager.
*
* @param \Phinx\Migration\Manager $manager
* @return \Phinx\Console\Command\AbstractCommand
*/
public function setManager(Manager $manager)
{
$this->manager = $manager;
return $this;
}
/**
* Gets the migration manager.
*
* @return \Phinx\Migration\Manager
*/
public function getManager()
{
return $this->manager;
}
/**
* Returns config file path
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @return string
*/
protected function locateConfigFile(InputInterface $input)
{
$configFile = $input->getOption('configuration');
$useDefault = false;
if ($configFile === null || $configFile === false) {
$useDefault = true;
}
$cwd = getcwd();
// locate the phinx config file (default: phinx.yml)
// TODO - In future walk the tree in reverse (max 10 levels)
$locator = new FileLocator([
$cwd . DIRECTORY_SEPARATOR
]);
if (!$useDefault) {
// Locate() throws an exception if the file does not exist
return $locator->locate($configFile, $cwd, $first = true);
}
$possibleConfigFiles = ['phinx.php', 'phinx.json', 'phinx.yml'];
foreach ($possibleConfigFiles as $configFile) {
try {
return $locator->locate($configFile, $cwd, $first = true);
} catch (\InvalidArgumentException $exception) {
$lastException = $exception;
}
}
throw $lastException;
}
/**
* Parse the config file and load it into the config object
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @throws \InvalidArgumentException
* @return void
*/
protected function loadConfig(InputInterface $input, OutputInterface $output)
{
$configFilePath = $this->locateConfigFile($input);
$output->writeln('using config file .' . str_replace(getcwd(), '', realpath($configFilePath)));
$parser = $input->getOption('parser');
// If no parser is specified try to determine the correct one from the file extension. Defaults to YAML
if ($parser === null) {
$extension = pathinfo($configFilePath, PATHINFO_EXTENSION);
switch (strtolower($extension)) {
case 'json':
$parser = 'json';
break;
case 'php':
$parser = 'php';
break;
case 'yml':
default:
$parser = 'yaml';
}
}
switch (strtolower($parser)) {
case 'json':
$config = Config::fromJson($configFilePath);
break;
case 'php':
$config = Config::fromPhp($configFilePath);
break;
case 'yaml':
$config = Config::fromYaml($configFilePath);
break;
default:
throw new \InvalidArgumentException(sprintf('\'%s\' is not a valid parser.', $parser));
}
$output->writeln('using config parser ' . $parser);
$this->setConfig($config);
}
/**
* Load the migrations manager and inject the config
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*/
protected function loadManager(InputInterface $input, OutputInterface $output)
{
if ($this->getManager() === null) {
$manager = new Manager($this->getConfig(), $input, $output);
$this->setManager($manager);
} else {
$manager = $this->getManager();
$manager->setInput($input);
$manager->setOutput($output);
}
}
/**
* Verify that the migration directory exists and is writable.
*
* @param string $path
* @throws \InvalidArgumentException
* @return void
*/
protected function verifyMigrationDirectory($path)
{
if (!is_dir($path)) {
throw new \InvalidArgumentException(sprintf(
'Migration directory "%s" does not exist',
$path
));
}
if (!is_writable($path)) {
throw new \InvalidArgumentException(sprintf(
'Migration directory "%s" is not writable',
$path
));
}
}
/**
* Verify that the seed directory exists and is writable.
*
* @param string $path
* @throws \InvalidArgumentException
* @return void
*/
protected function verifySeedDirectory($path)
{
if (!is_dir($path)) {
throw new \InvalidArgumentException(sprintf(
'Seed directory "%s" does not exist',
$path
));
}
if (!is_writable($path)) {
throw new \InvalidArgumentException(sprintf(
'Seed directory "%s" is not writable',
$path
));
}
}
/**
* Returns the migration template filename.
*
* @return string
*/
protected function getMigrationTemplateFilename()
{
return __DIR__ . self::DEFAULT_MIGRATION_TEMPLATE;
}
/**
* Returns the seed template filename.
*
* @return string
*/
protected function getSeedTemplateFilename()
{
return __DIR__ . self::DEFAULT_SEED_TEMPLATE;
}
}
phinx-0.9.2/src/Phinx/Console/Command/Breakpoint.php 0000664 0000000 0000000 00000007276 13217376123 0022335 0 ustar 00root root 0000000 0000000 addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment.');
$this->setName('breakpoint')
->setDescription('Manage breakpoints')
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to set or clear a breakpoint against')
->addOption('--remove-all', '-r', InputOption::VALUE_NONE, 'Remove all breakpoints')
->setHelp(
<<breakpoint command allows you to set or clear a breakpoint against a specific target to inhibit rollbacks beyond a certain target.
If no target is supplied then the most recent migration will be used.
You cannot specify un-migrated targets
phinx breakpoint -e development
phinx breakpoint -e development -t 20110103081132
phinx breakpoint -e development -r
EOT
);
}
/**
* Toggle the breakpoint.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
$environment = $input->getOption('environment');
$version = $input->getOption('target');
$removeAll = $input->getOption('remove-all');
if ($environment === null) {
$environment = $this->getConfig()->getDefaultEnvironment();
$output->writeln('warning no environment specified, defaulting to: ' . $environment);
} else {
$output->writeln('using environment ' . $environment);
}
if ($version && $removeAll) {
throw new \InvalidArgumentException('Cannot toggle a breakpoint and remove all breakpoints at the same time.');
}
// Remove all breakpoints
if ($removeAll) {
$this->getManager()->removeBreakpoints($environment);
} else {
// Toggle the breakpoint.
$this->getManager()->toggleBreakpoint($environment, $version);
}
}
}
phinx-0.9.2/src/Phinx/Console/Command/Create.php 0000664 0000000 0000000 00000030605 13217376123 0021432 0 ustar 00root root 0000000 0000000 setName('create')
->setDescription('Create a new migration')
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the migration (in CamelCase)?')
->setHelp(sprintf(
'%sCreates a new database migration%s',
PHP_EOL,
PHP_EOL
));
// An alternative template.
$this->addOption('template', 't', InputOption::VALUE_REQUIRED, 'Use an alternative template');
// A classname to be used to gain access to the template content as well as the ability to
// have a callback once the migration file has been created.
$this->addOption('class', 'l', InputOption::VALUE_REQUIRED, 'Use a class implementing "' . self::CREATION_INTERFACE . '" to generate the template');
// Allow the migration path to be chosen non-interactively.
$this->addOption('path', null, InputOption::VALUE_REQUIRED, 'Specify the path in which to create this migration');
}
/**
* Get the confirmation question asking if the user wants to create the
* migrations directory.
*
* @return \Symfony\Component\Console\Question\ConfirmationQuestion
*/
protected function getCreateMigrationDirectoryQuestion()
{
return new ConfirmationQuestion('Create migrations directory? [y]/n ', true);
}
/**
* Get the question that allows the user to select which migration path to use.
*
* @param string[] $paths
* @return \Symfony\Component\Console\Question\ChoiceQuestion
*/
protected function getSelectMigrationPathQuestion(array $paths)
{
return new ChoiceQuestion('Which migrations path would you like to use?', $paths, 0);
}
/**
* Returns the migration path to create the migration in.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return mixed
* @throws \Exception
*/
protected function getMigrationPath(InputInterface $input, OutputInterface $output)
{
// First, try the non-interactive option:
$path = $input->getOption('path');
if (!empty($path)) {
return $path;
}
$paths = $this->getConfig()->getMigrationPaths();
// No paths? That's a problem.
if (empty($paths)) {
throw new \Exception('No migration paths set in your Phinx configuration file.');
}
$paths = Util::globAll($paths);
if (empty($paths)) {
throw new \Exception(
'You probably used curly braces to define migration path in your Phinx configuration file, ' .
'but no directories have been matched using this pattern. ' .
'You need to create a migration directory manually.'
);
}
// Only one path set, so select that:
if (1 === count($paths)) {
return array_shift($paths);
}
// Ask the user which of their defined paths they'd like to use:
$helper = $this->getHelper('question');
$question = $this->getSelectMigrationPathQuestion($paths);
return $helper->ask($input, $output, $question);
}
/**
* Create the new migration.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
// get the migration path from the config
$path = $this->getMigrationPath($input, $output);
if (!file_exists($path)) {
$helper = $this->getHelper('question');
$question = $this->getCreateMigrationDirectoryQuestion();
if ($helper->ask($input, $output, $question)) {
mkdir($path, 0755, true);
}
}
$this->verifyMigrationDirectory($path);
$config = $this->getConfig();
$namespace = $config instanceof NamespaceAwareInterface ? $config->getMigrationNamespaceByPath($path) : null;
$path = realpath($path);
$className = $input->getArgument('name');
if (!Util::isValidPhinxClassName($className)) {
throw new \InvalidArgumentException(sprintf(
'The migration class name "%s" is invalid. Please use CamelCase format.',
$className
));
}
if (!Util::isUniqueMigrationClassName($className, $path)) {
throw new \InvalidArgumentException(sprintf(
'The migration class name "%s%s" already exists',
$namespace ? ($namespace . '\\') : '',
$className
));
}
// Compute the file path
$fileName = Util::mapClassNameToFileName($className);
$filePath = $path . DIRECTORY_SEPARATOR . $fileName;
if (is_file($filePath)) {
throw new \InvalidArgumentException(sprintf(
'The file "%s" already exists',
$filePath
));
}
// Get the alternative template and static class options from the config, but only allow one of them.
$defaultAltTemplate = $this->getConfig()->getTemplateFile();
$defaultCreationClassName = $this->getConfig()->getTemplateClass();
if ($defaultAltTemplate && $defaultCreationClassName) {
throw new \InvalidArgumentException('Cannot define template:class and template:file at the same time');
}
// Get the alternative template and static class options from the command line, but only allow one of them.
$altTemplate = $input->getOption('template');
$creationClassName = $input->getOption('class');
if ($altTemplate && $creationClassName) {
throw new \InvalidArgumentException('Cannot use --template and --class at the same time');
}
// If no commandline options then use the defaults.
if (!$altTemplate && !$creationClassName) {
$altTemplate = $defaultAltTemplate;
$creationClassName = $defaultCreationClassName;
}
// Verify the alternative template file's existence.
if ($altTemplate && !is_file($altTemplate)) {
throw new \InvalidArgumentException(sprintf(
'The alternative template file "%s" does not exist',
$altTemplate
));
}
// Verify that the template creation class (or the aliased class) exists and that it implements the required interface.
$aliasedClassName = null;
if ($creationClassName) {
// Supplied class does not exist, is it aliased?
if (!class_exists($creationClassName)) {
$aliasedClassName = $this->getConfig()->getAlias($creationClassName);
if ($aliasedClassName && !class_exists($aliasedClassName)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" via the alias "%s" does not exist',
$aliasedClassName,
$creationClassName
));
} elseif (!$aliasedClassName) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" does not exist',
$creationClassName
));
}
}
// Does the class implement the required interface?
if (!$aliasedClassName && !is_subclass_of($creationClassName, self::CREATION_INTERFACE)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" does not implement the required interface "%s"',
$creationClassName,
self::CREATION_INTERFACE
));
} elseif ($aliasedClassName && !is_subclass_of($aliasedClassName, self::CREATION_INTERFACE)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" via the alias "%s" does not implement the required interface "%s"',
$aliasedClassName,
$creationClassName,
self::CREATION_INTERFACE
));
}
}
// Use the aliased class.
$creationClassName = $aliasedClassName ?: $creationClassName;
// Determine the appropriate mechanism to get the template
if ($creationClassName) {
// Get the template from the creation class
$creationClass = new $creationClassName($input, $output);
$contents = $creationClass->getMigrationTemplate();
} else {
// Load the alternative template if it is defined.
$contents = file_get_contents($altTemplate ?: $this->getMigrationTemplateFilename());
}
// inject the class names appropriate to this migration
$classes = [
'$namespaceDefinition' => $namespace !== null ? ('namespace ' . $namespace . ';') : '',
'$namespace' => $namespace,
'$useClassName' => $this->getConfig()->getMigrationBaseClassName(false),
'$className' => $className,
'$version' => Util::getVersionFromFileName($fileName),
'$baseClassName' => $this->getConfig()->getMigrationBaseClassName(true),
];
$contents = strtr($contents, $classes);
if (file_put_contents($filePath, $contents) === false) {
throw new \RuntimeException(sprintf(
'The file "%s" could not be written to',
$path
));
}
// Do we need to do the post creation call to the creation class?
if (isset($creationClass)) {
$creationClass->postMigrationCreation($filePath, $className, $this->getConfig()->getMigrationBaseClassName());
}
$output->writeln('using migration base class ' . $classes['$useClassName']);
if (!empty($altTemplate)) {
$output->writeln('using alternative template ' . $altTemplate);
} elseif (!empty($creationClassName)) {
$output->writeln('using template creation class ' . $creationClassName);
} else {
$output->writeln('using default template');
}
$output->writeln('created ' . str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $filePath));
}
}
phinx-0.9.2/src/Phinx/Console/Command/Init.php 0000664 0000000 0000000 00000007151 13217376123 0021132 0 ustar 00root root 0000000 0000000 setName('init')
->setDescription('Initialize the application for Phinx')
->addArgument('path', InputArgument::OPTIONAL, 'Which path should we initialize for Phinx?')
->setHelp(sprintf(
'%sInitializes the application for Phinx%s',
PHP_EOL,
PHP_EOL
));
}
/**
* Initializes the application.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
// get the migration path from the config
$path = $input->getArgument('path');
if ($path === null) {
$path = getcwd();
}
$path = realpath($path);
if (!is_writable($path)) {
throw new \InvalidArgumentException(sprintf(
'The directory "%s" is not writable',
$path
));
}
// Compute the file path
$fileName = 'phinx.yml'; // TODO - maybe in the future we allow custom config names.
$filePath = $path . DIRECTORY_SEPARATOR . $fileName;
if (file_exists($filePath)) {
throw new \InvalidArgumentException(sprintf(
'The file "%s" already exists',
$filePath
));
}
// load the config template
if (is_dir(__DIR__ . '/../../../data/Phinx')) {
$contents = file_get_contents(__DIR__ . '/../../../data/Phinx/phinx.yml');
} else {
$contents = file_get_contents(__DIR__ . '/../../../../phinx.yml');
}
if (file_put_contents($filePath, $contents) === false) {
throw new \RuntimeException(sprintf(
'The file "%s" could not be written to',
$path
));
}
$output->writeln('created .' . str_replace(getcwd(), '', $filePath));
}
}
phinx-0.9.2/src/Phinx/Console/Command/Migrate.php 0000664 0000000 0000000 00000011223 13217376123 0021612 0 ustar 00root root 0000000 0000000 addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
$this->setName('migrate')
->setDescription('Migrate the database')
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to migrate to')
->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to migrate to')
->addOption('--dry-run', '-x', InputOption::VALUE_NONE, 'Dump query to standard output instead of executing it')
->setHelp(
<<migrate command runs all available migrations, optionally up to a specific version
phinx migrate -e development
phinx migrate -e development -t 20110103081132
phinx migrate -e development -d 20110103
phinx migrate -e development -v
EOT
);
}
/**
* Migrate the database.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return int integer 0 on success, or an error code.
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
$version = $input->getOption('target');
$environment = $input->getOption('environment');
$date = $input->getOption('date');
if ($environment === null) {
$environment = $this->getConfig()->getDefaultEnvironment();
$output->writeln('warning no environment specified, defaulting to: ' . $environment);
} else {
$output->writeln('using environment ' . $environment);
}
$envOptions = $this->getConfig()->getEnvironment($environment);
if (isset($envOptions['adapter'])) {
$output->writeln('using adapter ' . $envOptions['adapter']);
}
if (isset($envOptions['wrapper'])) {
$output->writeln('using wrapper ' . $envOptions['wrapper']);
}
if (isset($envOptions['name'])) {
$output->writeln('using database ' . $envOptions['name']);
} else {
$output->writeln('Could not determine database name! Please specify a database name in your config file.');
return 1;
}
if (isset($envOptions['table_prefix'])) {
$output->writeln('using table prefix ' . $envOptions['table_prefix']);
}
if (isset($envOptions['table_suffix'])) {
$output->writeln('using table suffix ' . $envOptions['table_suffix']);
}
// run the migrations
$start = microtime(true);
if ($date !== null) {
$this->getManager()->migrateToDateTime($environment, new \DateTime($date));
} else {
$this->getManager()->migrate($environment, $version);
}
$end = microtime(true);
$output->writeln('');
$output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '');
return 0;
}
}
phinx-0.9.2/src/Phinx/Console/Command/Rollback.php 0000664 0000000 0000000 00000014441 13217376123 0021760 0 ustar 00root root 0000000 0000000 addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
$this->setName('rollback')
->setDescription('Rollback the last or to a specific migration')
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to rollback to')
->addOption('--date', '-d', InputOption::VALUE_REQUIRED, 'The date to rollback to')
->addOption('--force', '-f', InputOption::VALUE_NONE, 'Force rollback to ignore breakpoints')
->addOption('--dry-run', '-x', InputOption::VALUE_NONE, 'Dump query to standard output instead of executing it')
->setHelp(
<<rollback command reverts the last migration, or optionally up to a specific version
phinx rollback -e development
phinx rollback -e development -t 20111018185412
phinx rollback -e development -d 20111018
phinx rollback -e development -v
phinx rollback -e development -t 20111018185412 -f
If you have a breakpoint set, then you can rollback to target 0 and the rollbacks will stop at the breakpoint.
phinx rollback -e development -t 0
The version_order configuration option is used to determine the order of the migrations when rolling back.
This can be used to allow the rolling back of the last executed migration instead of the last created one, or combined
with the -d|--date option to rollback to a certain date using the migration start times to order them.
EOT
);
}
/**
* Rollback the migration.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
$environment = $input->getOption('environment');
$version = $input->getOption('target');
$date = $input->getOption('date');
$force = (bool)$input->getOption('force');
$config = $this->getConfig();
if ($environment === null) {
$environment = $config->getDefaultEnvironment();
$output->writeln('warning no environment specified, defaulting to: ' . $environment);
} else {
$output->writeln('using environment ' . $environment);
}
$envOptions = $config->getEnvironment($environment);
if (isset($envOptions['adapter'])) {
$output->writeln('using adapter ' . $envOptions['adapter']);
}
if (isset($envOptions['wrapper'])) {
$output->writeln('using wrapper ' . $envOptions['wrapper']);
}
if (isset($envOptions['name'])) {
$output->writeln('using database ' . $envOptions['name']);
}
$versionOrder = $this->getConfig()->getVersionOrder();
$output->writeln('ordering by ' . $versionOrder . " time");
// rollback the specified environment
if ($date === null) {
$targetMustMatchVersion = true;
$target = $version;
} else {
$targetMustMatchVersion = false;
$target = $this->getTargetFromDate($date);
}
$start = microtime(true);
$this->getManager()->rollback($environment, $target, $force, $targetMustMatchVersion);
$end = microtime(true);
$output->writeln('');
$output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '');
}
/**
* Get Target from Date
*
* @param string $date The date to convert to a target.
* @return string The target
*/
public function getTargetFromDate($date)
{
if (!preg_match('/^\d{4,14}$/', $date)) {
throw new \InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
}
// what we need to append to the date according to the possible date string lengths
$dateStrlenToAppend = [
14 => '',
12 => '00',
10 => '0000',
8 => '000000',
6 => '01000000',
4 => '0101000000',
];
if (!isset($dateStrlenToAppend[strlen($date)])) {
throw new \InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
}
$target = $date . $dateStrlenToAppend[strlen($date)];
$dateTime = \DateTime::createFromFormat('YmdHis', $target);
if ($dateTime === false) {
throw new \InvalidArgumentException('Invalid date. Format is YYYY[MM[DD[HH[II[SS]]]]].');
}
return $dateTime->format('YmdHis');
}
}
phinx-0.9.2/src/Phinx/Console/Command/SeedCreate.php 0000664 0000000 0000000 00000015525 13217376123 0022237 0 ustar 00root root 0000000 0000000 setName('seed:create')
->setDescription('Create a new database seeder')
->addArgument('name', InputArgument::REQUIRED, 'What is the name of the seeder?')
->addOption('path', null, InputOption::VALUE_REQUIRED, 'Specify the path in which to create this seeder')
->setHelp(sprintf(
'%sCreates a new database seeder%s',
PHP_EOL,
PHP_EOL
));
}
/**
* Get the confirmation question asking if the user wants to create the
* seeds directory.
*
* @return \Symfony\Component\Console\Question\ConfirmationQuestion
*/
protected function getCreateSeedDirectoryQuestion()
{
return new ConfirmationQuestion('Create seeds directory? [y]/n ', true);
}
/**
* Get the question that allows the user to select which seed path to use.
*
* @param string[] $paths
* @return \Symfony\Component\Console\Question\ChoiceQuestion
*/
protected function getSelectSeedPathQuestion(array $paths)
{
return new ChoiceQuestion('Which seeds path would you like to use?', $paths, 0);
}
/**
* Returns the seed path to create the seeder in.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return mixed
* @throws \Exception
*/
protected function getSeedPath(InputInterface $input, OutputInterface $output)
{
// First, try the non-interactive option:
$path = $input->getOption('path');
if (!empty($path)) {
return $path;
}
$paths = $this->getConfig()->getSeedPaths();
// No paths? That's a problem.
if (empty($paths)) {
throw new \Exception('No seed paths set in your Phinx configuration file.');
}
$paths = Util::globAll($paths);
if (empty($paths)) {
throw new \Exception(
'You probably used curly braces to define seed path in your Phinx configuration file, ' .
'but no directories have been matched using this pattern. ' .
'You need to create a seed directory manually.'
);
}
// Only one path set, so select that:
if (1 === count($paths)) {
return array_shift($paths);
}
// Ask the user which of their defined paths they'd like to use:
$helper = $this->getHelper('question');
$question = $this->getSelectSeedPathQuestion($paths);
return $helper->ask($input, $output, $question);
}
/**
* Create the new seeder.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
// get the seed path from the config
$path = $this->getSeedPath($input, $output);
if (!file_exists($path)) {
$helper = $this->getHelper('question');
$question = $this->getCreateSeedDirectoryQuestion();
if ($helper->ask($input, $output, $question)) {
mkdir($path, 0755, true);
}
}
$this->verifySeedDirectory($path);
$path = realpath($path);
$className = $input->getArgument('name');
if (!Util::isValidPhinxClassName($className)) {
throw new \InvalidArgumentException(sprintf(
'The seed class name "%s" is invalid. Please use CamelCase format',
$className
));
}
// Compute the file path
$filePath = $path . DIRECTORY_SEPARATOR . $className . '.php';
if (is_file($filePath)) {
throw new \InvalidArgumentException(sprintf(
'The file "%s" already exists',
basename($filePath)
));
}
// inject the class names appropriate to this seeder
$contents = file_get_contents($this->getSeedTemplateFilename());
$config = $this->getConfig();
$namespace = $config instanceof NamespaceAwareInterface ? $config->getSeedNamespaceByPath($path) : null;
$classes = [
'$namespaceDefinition' => $namespace !== null ? ('namespace ' . $namespace . ';') : '',
'$namespace' => $namespace,
'$useClassName' => 'Phinx\Seed\AbstractSeed',
'$className' => $className,
'$baseClassName' => 'AbstractSeed',
];
$contents = strtr($contents, $classes);
if (file_put_contents($filePath, $contents) === false) {
throw new \RuntimeException(sprintf(
'The file "%s" could not be written to',
$path
));
}
$output->writeln('using seed base class ' . $classes['$useClassName']);
$output->writeln('created .' . str_replace(getcwd(), '', $filePath));
}
}
phinx-0.9.2/src/Phinx/Console/Command/SeedRun.php 0000664 0000000 0000000 00000010743 13217376123 0021575 0 ustar 00root root 0000000 0000000 addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
$this->setName('seed:run')
->setDescription('Run database seeders')
->addOption('--seed', '-s', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'What is the name of the seeder?')
->setHelp(
<<seed:run command runs all available or individual seeders
phinx seed:run -e development
phinx seed:run -e development -s UserSeeder
phinx seed:run -e development -s UserSeeder -s PermissionSeeder -s LogSeeder
phinx seed:run -e development -v
EOT
);
}
/**
* Run database seeders.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
$seedSet = $input->getOption('seed');
$environment = $input->getOption('environment');
if ($environment === null) {
$environment = $this->getConfig()->getDefaultEnvironment();
$output->writeln('warning no environment specified, defaulting to: ' . $environment);
} else {
$output->writeln('using environment ' . $environment);
}
$envOptions = $this->getConfig()->getEnvironment($environment);
if (isset($envOptions['adapter'])) {
$output->writeln('using adapter ' . $envOptions['adapter']);
}
if (isset($envOptions['wrapper'])) {
$output->writeln('using wrapper ' . $envOptions['wrapper']);
}
if (isset($envOptions['name'])) {
$output->writeln('using database ' . $envOptions['name']);
} else {
$output->writeln('Could not determine database name! Please specify a database name in your config file.');
return;
}
if (isset($envOptions['table_prefix'])) {
$output->writeln('using table prefix ' . $envOptions['table_prefix']);
}
if (isset($envOptions['table_suffix'])) {
$output->writeln('using table suffix ' . $envOptions['table_suffix']);
}
$start = microtime(true);
if (empty($seedSet)) {
// run all the seed(ers)
$this->getManager()->seed($environment);
} else {
// run seed(ers) specified in a comma-separated list of classes
foreach ($seedSet as $seed) {
$this->getManager()->seed($environment, trim($seed));
}
}
$end = microtime(true);
$output->writeln('');
$output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '');
}
}
phinx-0.9.2/src/Phinx/Console/Command/Status.php 0000664 0000000 0000000 00000006477 13217376123 0021524 0 ustar 00root root 0000000 0000000 addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment.');
$this->setName('status')
->setDescription('Show migration status')
->addOption('--format', '-f', InputOption::VALUE_REQUIRED, 'The output format: text or json. Defaults to text.')
->setHelp(
<<status command prints a list of all migrations, along with their current status
phinx status -e development
phinx status -e development -f json
The version_order configuration option is used to determine the order of the status migrations.
EOT
);
}
/**
* Show the migration status.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return int 0 if all migrations are up, or an error code
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->bootstrap($input, $output);
$environment = $input->getOption('environment');
$format = $input->getOption('format');
if ($environment === null) {
$environment = $this->getConfig()->getDefaultEnvironment();
$output->writeln('warning no environment specified, defaulting to: ' . $environment);
} else {
$output->writeln('using environment ' . $environment);
}
if ($format !== null) {
$output->writeln('using format ' . $format);
}
$output->writeln('ordering by ' . $this->getConfig()->getVersionOrder() . " time");
// print the status
return $this->getManager()->printStatus($environment, $format);
}
}
phinx-0.9.2/src/Phinx/Console/Command/Test.php 0000664 0000000 0000000 00000007103 13217376123 0021143 0 ustar 00root root 0000000 0000000
*/
class Test extends AbstractCommand
{
/**
* {@inheritdoc}
*/
protected function configure()
{
parent::configure();
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
$this->setName('test')
->setDescription('Verify the configuration file')
->setHelp(
<<test command verifies the YAML configuration file and optionally an environment
phinx test
phinx test -e development
EOT
);
}
/**
* Verify configuration file
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return void
*/
protected function execute(InputInterface $input, OutputInterface $output)
{
$this->loadConfig($input, $output);
$this->loadManager($input, $output);
// Verify the migrations path(s)
array_map(
[$this, 'verifyMigrationDirectory'],
Util::globAll($this->getConfig()->getMigrationPaths())
);
// Verify the seed path(s)
array_map(
[$this, 'verifySeedDirectory'],
Util::globAll($this->getConfig()->getSeedPaths())
);
$envName = $input->getOption('environment');
if ($envName) {
if (!$this->getConfig()->hasEnvironment($envName)) {
throw new \InvalidArgumentException(sprintf(
'The environment "%s" does not exist',
$envName
));
}
$output->writeln(sprintf('validating environment %s', $envName));
$environment = new Environment(
$envName,
$this->getConfig()->getEnvironment($envName)
);
// validate environment connection
$environment->getAdapter()->connect();
}
$output->writeln('success!');
}
}
phinx-0.9.2/src/Phinx/Console/PhinxApplication.php 0000664 0000000 0000000 00000006030 13217376123 0022116 0 ustar 00root root 0000000 0000000
*/
class PhinxApplication extends Application
{
/**
* Class Constructor.
*
* Initialize the Phinx console application.
*
* @param string $version The Application Version
*/
public function __construct()
{
$composerConfig = json_decode(file_get_contents(__DIR__ . '/../../../composer.json'));
$version = $composerConfig->version;
parent::__construct('Phinx by CakePHP - https://phinx.org.', $version);
$this->addCommands([
new Command\Init(),
new Command\Create(),
new Command\Migrate(),
new Command\Rollback(),
new Command\Status(),
new Command\Breakpoint(),
new Command\Test(),
new Command\SeedCreate(),
new Command\SeedRun(),
]);
}
/**
* Runs the current application.
*
* @param \Symfony\Component\Console\Input\InputInterface $input An Input instance
* @param \Symfony\Component\Console\Output\OutputInterface $output An Output instance
* @return int 0 if everything went fine, or an error code
*/
public function doRun(InputInterface $input, OutputInterface $output)
{
// always show the version information except when the user invokes the help
// command as that already does it
if ($input->hasParameterOption(['--help', '-h']) === false && $input->getFirstArgument() !== null) {
$output->writeln($this->getLongVersion());
$output->writeln('');
}
return parent::doRun($input, $output);
}
}
phinx-0.9.2/src/Phinx/Db/ 0000775 0000000 0000000 00000000000 13217376123 0015057 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Db/Adapter/ 0000775 0000000 0000000 00000000000 13217376123 0016437 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Db/Adapter/AbstractAdapter.php 0000664 0000000 0000000 00000014130 13217376123 0022213 0 ustar 00root root 0000000 0000000 setOptions($options);
if ($input !== null) {
$this->setInput($input);
}
if ($output !== null) {
$this->setOutput($output);
}
}
/**
* {@inheritdoc}
*/
public function setOptions(array $options)
{
$this->options = $options;
if (isset($options['default_migration_table'])) {
$this->setSchemaTableName($options['default_migration_table']);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return isset($this->options[$name]);
}
/**
* {@inheritdoc}
*/
public function getOption($name)
{
if (!$this->hasOption($name)) {
return null;
}
return $this->options[$name];
}
/**
* {@inheritdoc}
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* {@inheritdoc}
*/
public function getInput()
{
return $this->input;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
if ($this->output === null) {
$output = new NullOutput();
$this->setOutput($output);
}
return $this->output;
}
/**
* {@inheritdoc}
*
* @return array
*/
public function getVersions()
{
$rows = $this->getVersionLog();
return array_keys($rows);
}
/**
* Gets the schema table name.
*
* @return string
*/
public function getSchemaTableName()
{
return $this->schemaTableName;
}
/**
* Sets the schema table name.
*
* @param string $schemaTableName Schema Table Name
* @return $this
*/
public function setSchemaTableName($schemaTableName)
{
$this->schemaTableName = $schemaTableName;
return $this;
}
/**
* {@inheritdoc}
*/
public function hasSchemaTable()
{
return $this->hasTable($this->getSchemaTableName());
}
/**
* {@inheritdoc}
*/
public function createSchemaTable()
{
try {
$options = [
'id' => false,
'primary_key' => 'version'
];
$table = new Table($this->getSchemaTableName(), $options, $this);
$table->addColumn('version', 'biginteger')
->addColumn('migration_name', 'string', ['limit' => 100, 'default' => null, 'null' => true])
->addColumn('start_time', 'timestamp', ['default' => null, 'null' => true])
->addColumn('end_time', 'timestamp', ['default' => null, 'null' => true])
->addColumn('breakpoint', 'boolean', ['default' => false])
->save();
} catch (\Exception $exception) {
throw new \InvalidArgumentException('There was a problem creating the schema table: ' . $exception->getMessage());
}
}
/**
* {@inheritdoc}
*/
public function getAdapterType()
{
return $this->getOption('adapter');
}
/**
* {@inheritdoc}
*/
public function isValidColumnType(Column $column)
{
return in_array($column->getType(), $this->getColumnTypes());
}
/**
* Determines if instead of executing queries a dump to standard output is needed
*
* @return bool
*/
public function isDryRunEnabled()
{
$input = $this->getInput();
return ($input && $input->hasOption('dry-run')) ? $input->getOption('dry-run') : false;
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/AdapterFactory.php 0000664 0000000 0000000 00000012147 13217376123 0022065 0 ustar 00root root 0000000 0000000
*/
class AdapterFactory
{
/**
* @var \Phinx\Db\Adapter\AdapterFactory
*/
protected static $instance;
/**
* Get the factory singleton instance.
*
* @return \Phinx\Db\Adapter\AdapterFactory
*/
public static function instance()
{
if (!static::$instance) {
static::$instance = new static();
}
return static::$instance;
}
/**
* Class map of database adapters, indexed by PDO::ATTR_DRIVER_NAME.
*
* @var array
*/
protected $adapters = [
'mysql' => 'Phinx\Db\Adapter\MysqlAdapter',
'pgsql' => 'Phinx\Db\Adapter\PostgresAdapter',
'sqlite' => 'Phinx\Db\Adapter\SQLiteAdapter',
'sqlsrv' => 'Phinx\Db\Adapter\SqlServerAdapter',
];
/**
* Class map of adapters wrappers, indexed by name.
*
* @var array
*/
protected $wrappers = [
'prefix' => 'Phinx\Db\Adapter\TablePrefixAdapter',
'proxy' => 'Phinx\Db\Adapter\ProxyAdapter',
'timed' => 'Phinx\Db\Adapter\TimedOutputAdapter',
];
/**
* Add or replace an adapter with a fully qualified class name.
*
* @throws \RuntimeException
* @param string $name
* @param string $class
* @return $this
*/
public function registerAdapter($name, $class)
{
if (!is_subclass_of($class, 'Phinx\Db\Adapter\AdapterInterface')) {
throw new \RuntimeException(sprintf(
'Adapter class "%s" must implement Phinx\\Db\\Adapter\\AdapterInterface',
$class
));
}
$this->adapters[$name] = $class;
return $this;
}
/**
* Get an adapter class by name.
*
* @throws \RuntimeException
* @param string $name
* @return string
*/
protected function getClass($name)
{
if (empty($this->adapters[$name])) {
throw new \RuntimeException(sprintf(
'Adapter "%s" has not been registered',
$name
));
}
return $this->adapters[$name];
}
/**
* Get an adapter instance by name.
*
* @param string $name
* @param array $options
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter($name, array $options)
{
$class = $this->getClass($name);
return new $class($options);
}
/**
* Add or replace a wrapper with a fully qualified class name.
*
* @throws \RuntimeException
* @param string $name
* @param string $class
* @return $this
*/
public function registerWrapper($name, $class)
{
if (!is_subclass_of($class, 'Phinx\Db\Adapter\WrapperInterface')) {
throw new \RuntimeException(sprintf(
'Wrapper class "%s" must be implement Phinx\\Db\\Adapter\\WrapperInterface',
$class
));
}
$this->wrappers[$name] = $class;
return $this;
}
/**
* Get a wrapper class by name.
*
* @throws \RuntimeException
* @param string $name
* @return string
*/
protected function getWrapperClass($name)
{
if (empty($this->wrappers[$name])) {
throw new \RuntimeException(sprintf(
'Wrapper "%s" has not been registered',
$name
));
}
return $this->wrappers[$name];
}
/**
* Get a wrapper instance by name.
*
* @param string $name
* @param \Phinx\Db\Adapter\AdapterInterface $adapter
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getWrapper($name, AdapterInterface $adapter)
{
$class = $this->getWrapperClass($name);
return new $class($adapter);
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/AdapterInterface.php 0000664 0000000 0000000 00000034110 13217376123 0022350 0 ustar 00root root 0000000 0000000
* @method \PDO getConnection()
*/
interface AdapterInterface
{
const PHINX_TYPE_STRING = 'string';
const PHINX_TYPE_CHAR = 'char';
const PHINX_TYPE_TEXT = 'text';
const PHINX_TYPE_INTEGER = 'integer';
const PHINX_TYPE_BIG_INTEGER = 'biginteger';
const PHINX_TYPE_FLOAT = 'float';
const PHINX_TYPE_DECIMAL = 'decimal';
const PHINX_TYPE_DATETIME = 'datetime';
const PHINX_TYPE_TIMESTAMP = 'timestamp';
const PHINX_TYPE_TIME = 'time';
const PHINX_TYPE_DATE = 'date';
const PHINX_TYPE_BINARY = 'binary';
const PHINX_TYPE_VARBINARY = 'varbinary';
const PHINX_TYPE_BLOB = 'blob';
const PHINX_TYPE_BOOLEAN = 'boolean';
const PHINX_TYPE_JSON = 'json';
const PHINX_TYPE_JSONB = 'jsonb';
const PHINX_TYPE_UUID = 'uuid';
const PHINX_TYPE_FILESTREAM = 'filestream';
// Geospatial database types
const PHINX_TYPE_GEOMETRY = 'geometry';
const PHINX_TYPE_POINT = 'point';
const PHINX_TYPE_LINESTRING = 'linestring';
const PHINX_TYPE_POLYGON = 'polygon';
// only for mysql so far
const PHINX_TYPE_ENUM = 'enum';
const PHINX_TYPE_SET = 'set';
// only for postgresql so far
const PHINX_TYPE_CIDR = 'cidr';
const PHINX_TYPE_INET = 'inet';
const PHINX_TYPE_MACADDR = 'macaddr';
const PHINX_TYPE_INTERVAL = 'interval';
/**
* Get all migrated version numbers.
*
* @return array
*/
public function getVersions();
/**
* Get all migration log entries, indexed by version creation time and sorted ascendingly by the configuration's
* version order option
*
* @return array
*/
public function getVersionLog();
/**
* Set adapter configuration options.
*
* @param array $options
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function setOptions(array $options);
/**
* Get all adapter options.
*
* @return array
*/
public function getOptions();
/**
* Check if an option has been set.
*
* @param string $name
* @return bool
*/
public function hasOption($name);
/**
* Get a single adapter option, or null if the option does not exist.
*
* @param string $name
* @return mixed
*/
public function getOption($name);
/**
* Sets the console input.
*
* @param \Symfony\Component\Console\Input\InputInterface $input Input
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function setInput(InputInterface $input);
/**
* Gets the console input.
*
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput();
/**
* Sets the console output.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output Output
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function setOutput(OutputInterface $output);
/**
* Gets the console output.
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput();
/**
* Records a migration being run.
*
* @param \Phinx\Migration\MigrationInterface $migration Migration
* @param string $direction Direction
* @param int $startTime Start Time
* @param int $endTime End Time
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime);
/**
* Toggle a migration breakpoint.
*
* @param \Phinx\Migration\MigrationInterface $migration
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function toggleBreakpoint(MigrationInterface $migration);
/**
* Reset all migration breakpoints.
*
* @return int The number of breakpoints reset
*/
public function resetAllBreakpoints();
/**
* Does the schema table exist?
*
* @deprecated use hasTable instead.
* @return bool
*/
public function hasSchemaTable();
/**
* Creates the schema table.
*
* @return void
*/
public function createSchemaTable();
/**
* Returns the adapter type.
*
* @return string
*/
public function getAdapterType();
/**
* Initializes the database connection.
*
* @throws \RuntimeException When the requested database driver is not installed.
* @return void
*/
public function connect();
/**
* Closes the database connection.
*
* @return void
*/
public function disconnect();
/**
* Does the adapter support transactions?
*
* @return bool
*/
public function hasTransactions();
/**
* Begin a transaction.
*
* @return void
*/
public function beginTransaction();
/**
* Commit a transaction.
*
* @return void
*/
public function commitTransaction();
/**
* Rollback a transaction.
*
* @return void
*/
public function rollbackTransaction();
/**
* Executes a SQL statement and returns the number of affected rows.
*
* @param string $sql SQL
* @return int
*/
public function execute($sql);
/**
* Executes a SQL statement and returns the result as an array.
*
* @param string $sql SQL
* @return mixed
*/
public function query($sql);
/**
* Executes a query and returns only one row as an array.
*
* @param string $sql SQL
* @return array
*/
public function fetchRow($sql);
/**
* Executes a query and returns an array of rows.
*
* @param string $sql SQL
* @return array
*/
public function fetchAll($sql);
/**
* Inserts data into a table.
*
* @param \Phinx\Db\Table $table where to insert data
* @param array $row
* @return void
*/
public function insert(Table $table, $row);
/**
* Inserts data into a table in a bulk.
*
* @param \Phinx\Db\Table $table where to insert data
* @param array $rows
* @return void
*/
public function bulkinsert(Table $table, $rows);
/**
* Quotes a table name for use in a query.
*
* @param string $tableName Table Name
* @return string
*/
public function quoteTableName($tableName);
/**
* Quotes a column name for use in a query.
*
* @param string $columnName Table Name
* @return string
*/
public function quoteColumnName($columnName);
/**
* Checks to see if a table exists.
*
* @param string $tableName Table Name
* @return bool
*/
public function hasTable($tableName);
/**
* Creates the specified database table.
*
* @param \Phinx\Db\Table $table Table
* @return void
*/
public function createTable(Table $table);
/**
* Renames the specified database table.
*
* @param string $tableName Table Name
* @param string $newName New Name
* @return void
*/
public function renameTable($tableName, $newName);
/**
* Drops the specified database table.
*
* @param string $tableName Table Name
* @return void
*/
public function dropTable($tableName);
/**
* Truncates the specified table
*
* @param string $tableName
* @return void
*/
public function truncateTable($tableName);
/**
* Returns table columns
*
* @param string $tableName Table Name
* @return \Phinx\Db\Table\Column[]
*/
public function getColumns($tableName);
/**
* Checks to see if a column exists.
*
* @param string $tableName Table Name
* @param string $columnName Column Name
* @return bool
*/
public function hasColumn($tableName, $columnName);
/**
* Adds the specified column to a database table.
*
* @param \Phinx\Db\Table $table Table
* @param \Phinx\Db\Table\Column $column Column
* @return void
*/
public function addColumn(Table $table, Column $column);
/**
* Renames the specified column.
*
* @param string $tableName Table Name
* @param string $columnName Column Name
* @param string $newColumnName New Column Name
* @return void
*/
public function renameColumn($tableName, $columnName, $newColumnName);
/**
* Change a table column type.
*
* @param string $tableName Table Name
* @param string $columnName Column Name
* @param \Phinx\Db\Table\Column $newColumn New Column
* @return \Phinx\Db\Table
*/
public function changeColumn($tableName, $columnName, Column $newColumn);
/**
* Drops the specified column.
*
* @param string $tableName Table Name
* @param string $columnName Column Name
* @return void
*/
public function dropColumn($tableName, $columnName);
/**
* Checks to see if an index exists.
*
* @param string $tableName Table Name
* @param mixed $columns Column(s)
* @return bool
*/
public function hasIndex($tableName, $columns);
/**
* Checks to see if an index specified by name exists.
*
* @param string $tableName Table Name
* @param string $indexName
* @return bool
*/
public function hasIndexByName($tableName, $indexName);
/**
* Adds the specified index to a database table.
*
* @param \Phinx\Db\Table $table Table
* @param \Phinx\Db\Table\Index $index Index
* @return void
*/
public function addIndex(Table $table, Index $index);
/**
* Drops the specified index from a database table.
*
* @param string $tableName
* @param mixed $columns Column(s)
* @return void
*/
public function dropIndex($tableName, $columns);
/**
* Drops the index specified by name from a database table.
*
* @param string $tableName
* @param string $indexName
* @return void
*/
public function dropIndexByName($tableName, $indexName);
/**
* Checks to see if a foreign key exists.
*
* @param string $tableName
* @param string[] $columns Column(s)
* @param string $constraint Constraint name
* @return bool
*/
public function hasForeignKey($tableName, $columns, $constraint = null);
/**
* Adds the specified foreign key to a database table.
*
* @param \Phinx\Db\Table $table
* @param \Phinx\Db\Table\ForeignKey $foreignKey
* @return void
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey);
/**
* Drops the specified foreign key from a database table.
*
* @param string $tableName
* @param string[] $columns Column(s)
* @param string $constraint Constraint name
* @return void
*/
public function dropForeignKey($tableName, $columns, $constraint = null);
/**
* Returns an array of the supported Phinx column types.
*
* @return array
*/
public function getColumnTypes();
/**
* Checks that the given column is of a supported type.
*
* @param \Phinx\Db\Table\Column $column
* @return bool
*/
public function isValidColumnType(Column $column);
/**
* Converts the Phinx logical type to the adapter's SQL type.
*
* @param string $type
* @param int $limit
* @return string[]
*/
public function getSqlType($type, $limit = null);
/**
* Creates a new database.
*
* @param string $name Database Name
* @param array $options Options
* @return void
*/
public function createDatabase($name, $options = []);
/**
* Checks to see if a database exists.
*
* @param string $name Database Name
* @return bool
*/
public function hasDatabase($name);
/**
* Drops the specified database.
*
* @param string $name Database Name
* @return void
*/
public function dropDatabase($name);
/**
* Creates the specified schema or throws an exception
* if there is no support for it.
*
* @param string $schemaName Schema Name
* @return void
*/
public function createSchema($schemaName = 'public');
/**
* Drops the specified schema table or throws an exception
* if there is no support for it.
*
* @param string $schemaName Schema name
* @return void
*/
public function dropSchema($schemaName);
/**
* Cast a value to a boolean appropriate for the adapter.
*
* @param mixed $value The value to be cast
*
* @return mixed
*/
public function castToBool($value);
}
phinx-0.9.2/src/Phinx/Db/Adapter/AdapterWrapper.php 0000664 0000000 0000000 00000026207 13217376123 0022100 0 ustar 00root root 0000000 0000000
*/
abstract class AdapterWrapper implements AdapterInterface, WrapperInterface
{
/**
* @var \Phinx\Db\Adapter\AdapterInterface
*/
protected $adapter;
/**
* {@inheritdoc}
*/
public function __construct(AdapterInterface $adapter)
{
$this->setAdapter($adapter);
}
/**
* {@inheritdoc}
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* {@inheritdoc}
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* {@inheritdoc}
*/
public function setOptions(array $options)
{
$this->adapter->setOptions($options);
return $this;
}
/**
* {@inheritdoc}
*/
public function getOptions()
{
return $this->adapter->getOptions();
}
/**
* {@inheritdoc}
*/
public function hasOption($name)
{
return $this->adapter->hasOption($name);
}
/**
* {@inheritdoc}
*/
public function getOption($name)
{
return $this->adapter->getOption($name);
}
/**
* {@inheritdoc}
*/
public function setInput(InputInterface $input)
{
$this->adapter->setInput($input);
return $this;
}
/**
* {@inheritdoc}
*/
public function getInput()
{
return $this->adapter->getInput();
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output)
{
$this->adapter->setOutput($output);
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
return $this->adapter->getOutput();
}
/**
* {@inheritdoc}
*/
public function connect()
{
$this->getAdapter()->connect();
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
$this->getAdapter()->disconnect();
}
/**
* {@inheritdoc}
*/
public function execute($sql)
{
return $this->getAdapter()->execute($sql);
}
/**
* {@inheritdoc}
*/
public function query($sql)
{
return $this->getAdapter()->query($sql);
}
/**
* {@inheritdoc}
*/
public function insert(Table $table, $row)
{
$this->getAdapter()->insert($table, $row);
}
/**
* {@inheritdoc}
*/
public function bulkinsert(Table $table, $rows)
{
$this->getAdapter()->bulkinsert($table, $rows);
}
/**
* {@inheritdoc}
*/
public function fetchRow($sql)
{
return $this->getAdapter()->fetchRow($sql);
}
/**
* {@inheritdoc}
*/
public function fetchAll($sql)
{
return $this->getAdapter()->fetchAll($sql);
}
/**
* {@inheritdoc}
*/
public function getVersions()
{
return $this->getAdapter()->getVersions();
}
/**
* {@inheritdoc}
*/
public function getVersionLog()
{
return $this->getAdapter()->getVersionLog();
}
/**
* {@inheritdoc}
*/
public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
{
$this->getAdapter()->migrated($migration, $direction, $startTime, $endTime);
return $this;
}
/**
* @inheritDoc
*/
public function toggleBreakpoint(MigrationInterface $migration)
{
$this->getAdapter()->toggleBreakpoint($migration);
return $this;
}
/**
* @inheritDoc
*/
public function resetAllBreakpoints()
{
return $this->getAdapter()->resetAllBreakpoints();
}
/**
* {@inheritdoc}
*/
public function hasSchemaTable()
{
return $this->getAdapter()->hasSchemaTable();
}
/**
* {@inheritdoc}
*/
public function createSchemaTable()
{
$this->getAdapter()->createSchemaTable();
}
/**
* {@inheritdoc}
*/
public function getColumnTypes()
{
return $this->getAdapter()->getColumnTypes();
}
/**
* {@inheritdoc}
*/
public function isValidColumnType(Column $column)
{
return $this->getAdapter()->isValidColumnType($column);
}
/**
* {@inheritdoc}
*/
public function hasTransactions()
{
return $this->getAdapter()->hasTransactions();
}
/**
* {@inheritdoc}
*/
public function beginTransaction()
{
$this->getAdapter()->beginTransaction();
}
/**
* {@inheritdoc}
*/
public function commitTransaction()
{
$this->getAdapter()->commitTransaction();
}
/**
* {@inheritdoc}
*/
public function rollbackTransaction()
{
$this->getAdapter()->rollbackTransaction();
}
/**
* {@inheritdoc}
*/
public function quoteTableName($tableName)
{
return $this->getAdapter()->quoteTableName($tableName);
}
/**
* {@inheritdoc}
*/
public function quoteColumnName($columnName)
{
return $this->getAdapter()->quoteColumnName($columnName);
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
return $this->getAdapter()->hasTable($tableName);
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$this->getAdapter()->createTable($table);
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$this->getAdapter()->renameTable($tableName, $newTableName);
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->getAdapter()->dropTable($tableName);
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$this->getAdapter()->truncateTable($tableName);
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
return $this->getAdapter()->getColumns($tableName);
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
return $this->getAdapter()->hasColumn($tableName, $columnName);
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$this->getAdapter()->addColumn($table, $column);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$this->getAdapter()->renameColumn($tableName, $columnName, $newColumnName);
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
return $this->getAdapter()->changeColumn($tableName, $columnName, $newColumn);
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$this->getAdapter()->dropColumn($tableName, $columnName);
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
return $this->getAdapter()->hasIndex($tableName, $columns);
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
return $this->getAdapter()->hasIndexByName($tableName, $indexName);
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$this->getAdapter()->addIndex($table, $index);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
$this->getAdapter()->dropIndex($tableName, $columns);
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$this->getAdapter()->dropIndexByName($tableName, $indexName);
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
return $this->getAdapter()->hasForeignKey($tableName, $columns, $constraint);
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$this->getAdapter()->addForeignKey($table, $foreignKey);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
$this->getAdapter()->dropForeignKey($tableName, $columns, $constraint);
}
/**
* {@inheritdoc}
*/
public function getSqlType($type, $limit = null)
{
return $this->getAdapter()->getSqlType($type, $limit);
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
$this->getAdapter()->createDatabase($name, $options);
}
/**
* {@inheritdoc}
*/
public function hasDatabase($name)
{
$this->getAdapter()->hasDatabase($name);
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$this->getAdapter()->dropDatabase($name);
}
/**
* {@inheritdoc}
*/
public function createSchema($schemaName = 'public')
{
$this->getAdapter()->createSchema($schemaName);
}
/**
* {@inheritdoc}
*/
public function dropSchema($schemaName)
{
$this->getAdapter()->dropSchema($schemaName);
}
/**
* {@inheritdoc}
*/
public function castToBool($value)
{
return $this->getAdapter()->castToBool($value);
}
/**
* {@inheritdoc}
*/
public function getConnection()
{
return $this->getAdapter()->getConnection();
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/MysqlAdapter.php 0000664 0000000 0000000 00000105270 13217376123 0021563 0 ustar 00root root 0000000 0000000
*/
class MysqlAdapter extends PdoAdapter implements AdapterInterface
{
protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true, 'boolean' => true];
const TEXT_TINY = 255;
const TEXT_SMALL = 255; /* deprecated, alias of TEXT_TINY */
const TEXT_REGULAR = 65535;
const TEXT_MEDIUM = 16777215;
const TEXT_LONG = 4294967295;
// According to https://dev.mysql.com/doc/refman/5.0/en/blob.html BLOB sizes are the same as TEXT
const BLOB_TINY = 255;
const BLOB_SMALL = 255; /* deprecated, alias of BLOB_TINY */
const BLOB_REGULAR = 65535;
const BLOB_MEDIUM = 16777215;
const BLOB_LONG = 4294967295;
const INT_TINY = 255;
const INT_SMALL = 65535;
const INT_MEDIUM = 16777215;
const INT_REGULAR = 4294967295;
const INT_BIG = 18446744073709551615;
const TYPE_YEAR = 'year';
/**
* {@inheritdoc}
*/
public function connect()
{
if ($this->connection === null) {
if (!class_exists('PDO') || !in_array('mysql', \PDO::getAvailableDrivers(), true)) {
// @codeCoverageIgnoreStart
throw new \RuntimeException('You need to enable the PDO_Mysql extension for Phinx to run properly.');
// @codeCoverageIgnoreEnd
}
$db = null;
$options = $this->getOptions();
$dsn = 'mysql:';
if (!empty($options['unix_socket'])) {
// use socket connection
$dsn .= 'unix_socket=' . $options['unix_socket'];
} else {
// use network connection
$dsn .= 'host=' . $options['host'];
if (!empty($options['port'])) {
$dsn .= ';port=' . $options['port'];
}
}
$dsn .= ';dbname=' . $options['name'];
// charset support
if (!empty($options['charset'])) {
$dsn .= ';charset=' . $options['charset'];
}
$driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
// support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO
// http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants
foreach ($options as $key => $option) {
if (strpos($key, 'mysql_attr_') === 0) {
$driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
}
}
try {
$db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
} catch (\PDOException $exception) {
throw new \InvalidArgumentException(sprintf(
'There was a problem connecting to the database: %s',
$exception->getMessage()
));
}
$this->setConnection($db);
}
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
$this->connection = null;
}
/**
* {@inheritdoc}
*/
public function hasTransactions()
{
return true;
}
/**
* {@inheritdoc}
*/
public function beginTransaction()
{
$this->execute('START TRANSACTION');
}
/**
* {@inheritdoc}
*/
public function commitTransaction()
{
$this->execute('COMMIT');
}
/**
* {@inheritdoc}
*/
public function rollbackTransaction()
{
$this->execute('ROLLBACK');
}
/**
* {@inheritdoc}
*/
public function quoteTableName($tableName)
{
return str_replace('.', '`.`', $this->quoteColumnName($tableName));
}
/**
* {@inheritdoc}
*/
public function quoteColumnName($columnName)
{
return '`' . str_replace('`', '``', $columnName) . '`';
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
$options = $this->getOptions();
$exists = $this->fetchRow(sprintf(
"SELECT TABLE_NAME
FROM INFORMATION_SCHEMA.TABLES
WHERE TABLE_SCHEMA = '%s' AND TABLE_NAME = '%s'",
$options['name'],
$tableName
));
return !empty($exists);
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
// This method is based on the MySQL docs here: http://dev.mysql.com/doc/refman/5.1/en/create-index.html
$defaultOptions = [
'engine' => 'InnoDB',
'collation' => 'utf8_general_ci'
];
$options = array_merge(
$defaultOptions,
array_intersect_key($this->getOptions(), $defaultOptions),
$table->getOptions()
);
// Add the default primary key
$columns = $table->getPendingColumns();
if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
$column = new Column();
$column->setName('id')
->setType('integer')
->setSigned(isset($options['signed']) ? $options['signed'] : true)
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = 'id';
} elseif (isset($options['id']) && is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = $options['id'];
}
// TODO - process table options like collation etc
// process table engine (default to InnoDB)
$optionsStr = 'ENGINE = InnoDB';
if (isset($options['engine'])) {
$optionsStr = sprintf('ENGINE = %s', $options['engine']);
}
// process table collation
if (isset($options['collation'])) {
$charset = explode('_', $options['collation']);
$optionsStr .= sprintf(' CHARACTER SET %s', $charset[0]);
$optionsStr .= sprintf(' COLLATE %s', $options['collation']);
}
// set the table comment
if (isset($options['comment'])) {
$optionsStr .= sprintf(" COMMENT=%s ", $this->getConnection()->quote($options['comment']));
}
$sql = 'CREATE TABLE ';
$sql .= $this->quoteTableName($table->getName()) . ' (';
foreach ($columns as $column) {
$sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
}
// set the primary key(s)
if (isset($options['primary_key'])) {
$sql = rtrim($sql);
$sql .= ' PRIMARY KEY (';
if (is_string($options['primary_key'])) { // handle primary_key => 'id'
$sql .= $this->quoteColumnName($options['primary_key']);
} elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
$sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
}
$sql .= ')';
} else {
$sql = substr(rtrim($sql), 0, -1); // no primary keys
}
// set the indexes
$indexes = $table->getIndexes();
foreach ($indexes as $index) {
$sql .= ', ' . $this->getIndexSqlDefinition($index);
}
// set the foreign keys
$foreignKeys = $table->getForeignKeys();
foreach ($foreignKeys as $foreignKey) {
$sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey);
}
$sql .= ') ' . $optionsStr;
$sql = rtrim($sql) . ';';
// execute the sql
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$this->execute(sprintf('RENAME TABLE %s TO %s', $this->quoteTableName($tableName), $this->quoteTableName($newTableName)));
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$sql = sprintf(
'TRUNCATE TABLE %s',
$this->quoteTableName($tableName)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
$columns = [];
$rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
foreach ($rows as $columnInfo) {
$phinxType = $this->getPhinxType($columnInfo['Type']);
$column = new Column();
$column->setName($columnInfo['Field'])
->setNull($columnInfo['Null'] !== 'NO')
->setDefault($columnInfo['Default'])
->setType($phinxType['name'])
->setLimit($phinxType['limit']);
if ($columnInfo['Extra'] === 'auto_increment') {
$column->setIdentity(true);
}
if (isset($phinxType['values'])) {
$column->setValues($phinxType['values']);
}
$columns[] = $column;
}
return $columns;
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
$rows = $this->fetchAll(sprintf('SHOW COLUMNS FROM %s', $this->quoteTableName($tableName)));
foreach ($rows as $column) {
if (strcasecmp($column['Field'], $columnName) === 0) {
return true;
}
}
return false;
}
/**
* Get the defintion for a `DEFAULT` statement.
*
* @param mixed $default
* @return string
*/
protected function getDefaultValueDefinition($default)
{
if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
$default = $this->getConnection()->quote($default);
} elseif (is_bool($default)) {
$default = $this->castToBool($default);
}
return isset($default) ? ' DEFAULT ' . $default : '';
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$sql = sprintf(
'ALTER TABLE %s ADD %s %s',
$this->quoteTableName($table->getName()),
$this->quoteColumnName($column->getName()),
$this->getColumnSqlDefinition($column)
);
if ($column->getAfter()) {
$sql .= ' AFTER ' . $this->quoteColumnName($column->getAfter());
}
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$rows = $this->fetchAll(sprintf('DESCRIBE %s', $this->quoteTableName($tableName)));
foreach ($rows as $row) {
if (strcasecmp($row['Field'], $columnName) === 0) {
$null = ($row['Null'] == 'NO') ? 'NOT NULL' : 'NULL';
$extra = ' ' . strtoupper($row['Extra']);
if (!is_null($row['Default'])) {
$extra .= $this->getDefaultValueDefinition($row['Default']);
}
$definition = $row['Type'] . ' ' . $null . $extra;
$this->execute(
sprintf(
'ALTER TABLE %s CHANGE COLUMN %s %s %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumnName),
$definition
)
);
return;
}
}
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: ' .
$columnName
));
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
$after = $newColumn->getAfter() ? ' AFTER ' . $this->quoteColumnName($newColumn->getAfter()) : '';
$this->execute(
sprintf(
'ALTER TABLE %s CHANGE %s %s %s%s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumn->getName()),
$this->getColumnSqlDefinition($newColumn),
$after
)
);
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$this->execute(
sprintf(
'ALTER TABLE %s DROP COLUMN %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName)
)
);
}
/**
* Get an array of indexes from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getIndexes($tableName)
{
$indexes = [];
$rows = $this->fetchAll(sprintf('SHOW INDEXES FROM %s', $this->quoteTableName($tableName)));
foreach ($rows as $row) {
if (!isset($indexes[$row['Key_name']])) {
$indexes[$row['Key_name']] = ['columns' => []];
}
$indexes[$row['Key_name']]['columns'][] = strtolower($row['Column_name']);
}
return $indexes;
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$columns = array_map('strtolower', $columns);
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
if ($columns == $index['columns']) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $name => $index) {
if ($name === $indexName) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$this->execute(
sprintf(
'ALTER TABLE %s ADD %s',
$this->quoteTableName($table->getName()),
$this->getIndexSqlDefinition($index)
)
);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$indexes = $this->getIndexes($tableName);
$columns = array_map('strtolower', $columns);
foreach ($indexes as $indexName => $index) {
if ($columns == $index['columns']) {
$this->execute(
sprintf(
'ALTER TABLE %s DROP INDEX %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($indexName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $name => $index) {
//$a = array_diff($columns, $index['columns']);
if ($name === $indexName) {
$this->execute(
sprintf(
'ALTER TABLE %s DROP INDEX %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($indexName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$foreignKeys = $this->getForeignKeys($tableName);
if ($constraint) {
if (isset($foreignKeys[$constraint])) {
return !empty($foreignKeys[$constraint]);
}
return false;
} else {
foreach ($foreignKeys as $key) {
if ($columns == $key['columns']) {
return true;
}
}
return false;
}
}
/**
* Get an array of foreign keys from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getForeignKeys($tableName)
{
$foreignKeys = [];
$rows = $this->fetchAll(sprintf(
"SELECT
CONSTRAINT_NAME,
TABLE_NAME,
COLUMN_NAME,
REFERENCED_TABLE_NAME,
REFERENCED_COLUMN_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
AND REFERENCED_TABLE_NAME IS NOT NULL
AND TABLE_NAME = '%s'
ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
$tableName
));
foreach ($rows as $row) {
$foreignKeys[$row['CONSTRAINT_NAME']]['table'] = $row['TABLE_NAME'];
$foreignKeys[$row['CONSTRAINT_NAME']]['columns'][] = $row['COLUMN_NAME'];
$foreignKeys[$row['CONSTRAINT_NAME']]['referenced_table'] = $row['REFERENCED_TABLE_NAME'];
$foreignKeys[$row['CONSTRAINT_NAME']]['referenced_columns'][] = $row['REFERENCED_COLUMN_NAME'];
}
return $foreignKeys;
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$this->execute(
sprintf(
'ALTER TABLE %s ADD %s',
$this->quoteTableName($table->getName()),
$this->getForeignKeySqlDefinition($foreignKey)
)
);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
if ($constraint) {
$this->execute(
sprintf(
'ALTER TABLE %s DROP FOREIGN KEY %s',
$this->quoteTableName($tableName),
$constraint
)
);
return;
} else {
foreach ($columns as $column) {
$rows = $this->fetchAll(sprintf(
"SELECT
CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE REFERENCED_TABLE_SCHEMA = DATABASE()
AND REFERENCED_TABLE_NAME IS NOT NULL
AND TABLE_NAME = '%s'
AND COLUMN_NAME = '%s'
ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
$tableName,
$column
));
foreach ($rows as $row) {
$this->dropForeignKey($tableName, $columns, $row['CONSTRAINT_NAME']);
}
}
}
}
/**
* {@inheritdoc}
*/
public function getSqlType($type, $limit = null)
{
switch ($type) {
case static::PHINX_TYPE_STRING:
return ['name' => 'varchar', 'limit' => $limit ?: 255];
case static::PHINX_TYPE_CHAR:
return ['name' => 'char', 'limit' => $limit ?: 255];
case static::PHINX_TYPE_TEXT:
if ($limit) {
$sizes = [
// Order matters! Size must always be tested from longest to shortest!
'longtext' => static::TEXT_LONG,
'mediumtext' => static::TEXT_MEDIUM,
'text' => static::TEXT_REGULAR,
'tinytext' => static::TEXT_SMALL,
];
foreach ($sizes as $name => $length) {
if ($limit >= $length) {
return ['name' => $name];
}
}
}
return ['name' => 'text'];
case static::PHINX_TYPE_BINARY:
return ['name' => 'binary', 'limit' => $limit ?: 255];
case static::PHINX_TYPE_VARBINARY:
return ['name' => 'varbinary', 'limit' => $limit ?: 255];
case static::PHINX_TYPE_BLOB:
if ($limit) {
$sizes = [
// Order matters! Size must always be tested from longest to shortest!
'longblob' => static::BLOB_LONG,
'mediumblob' => static::BLOB_MEDIUM,
'blob' => static::BLOB_REGULAR,
'tinyblob' => static::BLOB_SMALL,
];
foreach ($sizes as $name => $length) {
if ($limit >= $length) {
return ['name' => $name];
}
}
}
return ['name' => 'blob'];
case static::PHINX_TYPE_INTEGER:
if ($limit && $limit >= static::INT_TINY) {
$sizes = [
// Order matters! Size must always be tested from longest to shortest!
'bigint' => static::INT_BIG,
'int' => static::INT_REGULAR,
'mediumint' => static::INT_MEDIUM,
'smallint' => static::INT_SMALL,
'tinyint' => static::INT_TINY,
];
$limits = [
'int' => 11,
'bigint' => 20,
];
foreach ($sizes as $name => $length) {
if ($limit >= $length) {
$def = ['name' => $name];
if (isset($limits[$name])) {
$def['limit'] = $limits[$name];
}
return $def;
}
}
} elseif (!$limit) {
$limit = 11;
}
return ['name' => 'int', 'limit' => $limit];
case static::PHINX_TYPE_BIG_INTEGER:
return ['name' => 'bigint', 'limit' => 20];
case static::PHINX_TYPE_FLOAT:
return ['name' => 'float'];
case static::PHINX_TYPE_DECIMAL:
return ['name' => 'decimal'];
case static::PHINX_TYPE_DATETIME:
return ['name' => 'datetime'];
case static::PHINX_TYPE_TIMESTAMP:
return ['name' => 'timestamp'];
case static::PHINX_TYPE_TIME:
return ['name' => 'time'];
case static::PHINX_TYPE_DATE:
return ['name' => 'date'];
case static::PHINX_TYPE_BOOLEAN:
return ['name' => 'tinyint', 'limit' => 1];
case static::PHINX_TYPE_UUID:
return ['name' => 'char', 'limit' => 36];
// Geospatial database types
case static::PHINX_TYPE_GEOMETRY:
case static::PHINX_TYPE_POINT:
case static::PHINX_TYPE_LINESTRING:
case static::PHINX_TYPE_POLYGON:
return ['name' => $type];
case static::PHINX_TYPE_ENUM:
return ['name' => 'enum'];
case static::PHINX_TYPE_SET:
return ['name' => 'set'];
case static::TYPE_YEAR:
if (!$limit || in_array($limit, [2, 4])) {
$limit = 4;
}
return ['name' => 'year', 'limit' => $limit];
case static::PHINX_TYPE_JSON:
return ['name' => 'json'];
default:
throw new \RuntimeException('The type: "' . $type . '" is not supported.');
}
}
/**
* Returns Phinx type by SQL type
*
* @param string $sqlTypeDef
* @throws \RuntimeException
* @internal param string $sqlType SQL type
* @returns string Phinx type
*/
public function getPhinxType($sqlTypeDef)
{
$matches = [];
if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*(.+)*$/', $sqlTypeDef, $matches)) {
throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
} else {
$limit = null;
$precision = null;
$type = $matches[1];
if (count($matches) > 2) {
$limit = $matches[3] ? (int)$matches[3] : null;
}
if (count($matches) > 4) {
$precision = (int)$matches[5];
}
if ($type === 'tinyint' && $limit === 1) {
$type = static::PHINX_TYPE_BOOLEAN;
$limit = null;
}
switch ($type) {
case 'varchar':
$type = static::PHINX_TYPE_STRING;
if ($limit === 255) {
$limit = null;
}
break;
case 'char':
$type = static::PHINX_TYPE_CHAR;
if ($limit === 255) {
$limit = null;
}
if ($limit === 36) {
$type = static::PHINX_TYPE_UUID;
}
break;
case 'tinyint':
$type = static::PHINX_TYPE_INTEGER;
$limit = static::INT_TINY;
break;
case 'smallint':
$type = static::PHINX_TYPE_INTEGER;
$limit = static::INT_SMALL;
break;
case 'mediumint':
$type = static::PHINX_TYPE_INTEGER;
$limit = static::INT_MEDIUM;
break;
case 'int':
$type = static::PHINX_TYPE_INTEGER;
if ($limit === 11) {
$limit = null;
}
break;
case 'bigint':
if ($limit === 20) {
$limit = null;
}
$type = static::PHINX_TYPE_BIG_INTEGER;
break;
case 'blob':
$type = static::PHINX_TYPE_BINARY;
break;
case 'tinyblob':
$type = static::PHINX_TYPE_BINARY;
$limit = static::BLOB_TINY;
break;
case 'mediumblob':
$type = static::PHINX_TYPE_BINARY;
$limit = static::BLOB_MEDIUM;
break;
case 'longblob':
$type = static::PHINX_TYPE_BINARY;
$limit = static::BLOB_LONG;
break;
case 'tinytext':
$type = static::PHINX_TYPE_TEXT;
$limit = static::TEXT_TINY;
break;
case 'mediumtext':
$type = static::PHINX_TYPE_TEXT;
$limit = static::TEXT_MEDIUM;
break;
case 'longtext':
$type = static::PHINX_TYPE_TEXT;
$limit = static::TEXT_LONG;
break;
}
// Call this to check if parsed type is supported.
$this->getSqlType($type, $limit);
$phinxType = [
'name' => $type,
'limit' => $limit,
'precision' => $precision
];
if (static::PHINX_TYPE_ENUM == $type) {
$phinxType['values'] = explode("','", trim($matches[6], "()'"));
}
return $phinxType;
}
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
$charset = isset($options['charset']) ? $options['charset'] : 'utf8';
if (isset($options['collation'])) {
$this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s` COLLATE `%s`', $name, $charset, $options['collation']));
} else {
$this->execute(sprintf('CREATE DATABASE `%s` DEFAULT CHARACTER SET `%s`', $name, $charset));
}
}
/**
* {@inheritdoc}
*/
public function hasDatabase($name)
{
$rows = $this->fetchAll(
sprintf(
'SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = \'%s\'',
$name
)
);
foreach ($rows as $row) {
if (!empty($row)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$this->execute(sprintf('DROP DATABASE IF EXISTS `%s`', $name));
}
/**
* Gets the MySQL Column Definition for a Column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @return string
*/
protected function getColumnSqlDefinition(Column $column)
{
$sqlType = $this->getSqlType($column->getType(), $column->getLimit());
$def = '';
$def .= strtoupper($sqlType['name']);
if ($column->getPrecision() && $column->getScale()) {
$def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
} elseif (isset($sqlType['limit'])) {
$def .= '(' . $sqlType['limit'] . ')';
}
if (($values = $column->getValues()) && is_array($values)) {
$def .= "('" . implode("', '", $values) . "')";
}
$def .= $column->getEncoding() ? ' CHARACTER SET ' . $column->getEncoding() : '';
$def .= $column->getCollation() ? ' COLLATE ' . $column->getCollation() : '';
$def .= (!$column->isSigned() && isset($this->signedColumnTypes[$column->getType()])) ? ' unsigned' : '';
$def .= ($column->isNull() == false) ? ' NOT NULL' : ' NULL';
$def .= ($column->isIdentity()) ? ' AUTO_INCREMENT' : '';
$def .= $this->getDefaultValueDefinition($column->getDefault());
if ($column->getComment()) {
$def .= ' COMMENT ' . $this->getConnection()->quote($column->getComment());
}
if ($column->getUpdate()) {
$def .= ' ON UPDATE ' . $column->getUpdate();
}
return $def;
}
/**
* Gets the MySQL Index Definition for an Index object.
*
* @param \Phinx\Db\Table\Index $index Index
* @return string
*/
protected function getIndexSqlDefinition(Index $index)
{
$def = '';
$limit = '';
if ($index->getLimit()) {
$limit = '(' . $index->getLimit() . ')';
}
if ($index->getType() == Index::UNIQUE) {
$def .= ' UNIQUE';
}
if ($index->getType() == Index::FULLTEXT) {
$def .= ' FULLTEXT';
}
$def .= ' KEY';
if (is_string($index->getName())) {
$def .= ' `' . $index->getName() . '`';
}
$def .= ' (`' . implode('`,`', $index->getColumns()) . '`' . $limit . ')';
return $def;
}
/**
* Gets the MySQL Foreign Key Definition for an ForeignKey object.
*
* @param \Phinx\Db\Table\ForeignKey $foreignKey
* @return string
*/
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey)
{
$def = '';
if ($foreignKey->getConstraint()) {
$def .= ' CONSTRAINT ' . $this->quoteColumnName($foreignKey->getConstraint());
}
$columnNames = [];
foreach ($foreignKey->getColumns() as $column) {
$columnNames[] = $this->quoteColumnName($column);
}
$def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
$refColumnNames = [];
foreach ($foreignKey->getReferencedColumns() as $column) {
$refColumnNames[] = $this->quoteColumnName($column);
}
$def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
if ($foreignKey->getOnDelete()) {
$def .= ' ON DELETE ' . $foreignKey->getOnDelete();
}
if ($foreignKey->getOnUpdate()) {
$def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
}
return $def;
}
/**
* Describes a database table. This is a MySQL adapter specific method.
*
* @param string $tableName Table name
* @return array
*/
public function describeTable($tableName)
{
$options = $this->getOptions();
// mysql specific
$sql = sprintf(
"SELECT *
FROM information_schema.tables
WHERE table_schema = '%s'
AND table_name = '%s'",
$options['name'],
$tableName
);
return $this->fetchRow($sql);
}
/**
* Returns MySQL column types (inherited and MySQL specified).
* @return array
*/
public function getColumnTypes()
{
return array_merge(parent::getColumnTypes(), ['enum', 'set', 'year', 'json']);
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/PdoAdapter.php 0000664 0000000 0000000 00000023340 13217376123 0021175 0 ustar 00root root 0000000 0000000
*/
abstract class PdoAdapter extends AbstractAdapter
{
/**
* @var \PDO|null
*/
protected $connection;
/**
* {@inheritdoc}
*/
public function setOptions(array $options)
{
parent::setOptions($options);
if (isset($options['connection'])) {
$this->setConnection($options['connection']);
}
return $this;
}
/**
* Sets the database connection.
*
* @param \PDO $connection Connection
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function setConnection(\PDO $connection)
{
$this->connection = $connection;
// Create the schema table if it doesn't already exist
if (!$this->hasSchemaTable()) {
$this->createSchemaTable();
} else {
$table = new Table($this->getSchemaTableName(), [], $this);
if (!$table->hasColumn('migration_name')) {
$table
->addColumn(
'migration_name',
'string',
['limit' => 100, 'after' => 'version', 'default' => null, 'null' => true]
)
->save();
}
if (!$table->hasColumn('breakpoint')) {
$table
->addColumn('breakpoint', 'boolean', ['default' => false])
->save();
}
}
return $this;
}
/**
* Gets the database connection
*
* @return \PDO
*/
public function getConnection()
{
if ($this->connection === null) {
$this->connect();
}
return $this->connection;
}
/**
* {@inheritdoc}
*/
public function connect()
{
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
}
/**
* {@inheritdoc}
*/
public function execute($sql)
{
if ($this->isDryRunEnabled()) {
$this->getOutput()->writeln($sql);
return 0;
}
return $this->getConnection()->exec($sql);
}
/**
* Executes a query and returns PDOStatement.
*
* @param string $sql SQL
* @return \PDOStatement
*/
public function query($sql)
{
return $this->getConnection()->query($sql);
}
/**
* {@inheritdoc}
*/
public function fetchRow($sql)
{
$result = $this->query($sql);
return $result->fetch();
}
/**
* {@inheritdoc}
*/
public function fetchAll($sql)
{
$rows = [];
$result = $this->query($sql);
while ($row = $result->fetch()) {
$rows[] = $row;
}
return $rows;
}
/**
* {@inheritdoc}
*/
public function insert(Table $table, $row)
{
$sql = sprintf(
"INSERT INTO %s ",
$this->quoteTableName($table->getName())
);
$columns = array_keys($row);
$sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ")";
$sql .= " VALUES (" . implode(', ', array_fill(0, count($columns), '?')) . ")";
$stmt = $this->getConnection()->prepare($sql);
$stmt->execute(array_values($row));
}
/**
* {@inheritdoc}
*/
public function bulkinsert(Table $table, $rows)
{
$sql = sprintf(
"INSERT INTO %s ",
$this->quoteTableName($table->getName())
);
$current = current($rows);
$keys = array_keys($current);
$sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $keys)) . ") VALUES";
$vals = [];
foreach ($rows as $row) {
foreach ($row as $v) {
$vals[] = $v;
}
}
$count_keys = count($keys);
$query = "(" . implode(', ', array_fill(0, $count_keys, '?')) . ")";
$count_vars = count($rows);
$queries = array_fill(0, $count_vars, $query);
$sql .= implode(',', $queries);
$stmt = $this->getConnection()->prepare($sql);
$stmt->execute($vals);
}
/**
* {@inheritdoc}
*/
public function getVersions()
{
$rows = $this->getVersionLog();
return array_keys($rows);
}
/**
* {@inheritdoc}
*/
public function getVersionLog()
{
$result = [];
switch ($this->options['version_order']) {
case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
$orderBy = 'version ASC';
break;
case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
$orderBy = 'start_time ASC, version ASC';
break;
default:
throw new \RuntimeException('Invalid version_order configuration option');
}
$rows = $this->fetchAll(sprintf('SELECT * FROM %s ORDER BY %s', $this->getSchemaTableName(), $orderBy));
foreach ($rows as $version) {
$result[$version['version']] = $version;
}
return $result;
}
/**
* {@inheritdoc}
*/
public function migrated(MigrationInterface $migration, $direction, $startTime, $endTime)
{
if (strcasecmp($direction, MigrationInterface::UP) === 0) {
// up
$sql = sprintf(
"INSERT INTO %s (%s, %s, %s, %s, %s) VALUES ('%s', '%s', '%s', '%s', %s);",
$this->getSchemaTableName(),
$this->quoteColumnName('version'),
$this->quoteColumnName('migration_name'),
$this->quoteColumnName('start_time'),
$this->quoteColumnName('end_time'),
$this->quoteColumnName('breakpoint'),
$migration->getVersion(),
substr($migration->getName(), 0, 100),
$startTime,
$endTime,
$this->castToBool(false)
);
$this->execute($sql);
} else {
// down
$sql = sprintf(
"DELETE FROM %s WHERE %s = '%s'",
$this->getSchemaTableName(),
$this->quoteColumnName('version'),
$migration->getVersion()
);
$this->execute($sql);
}
return $this;
}
/**
* @inheritDoc
*/
public function toggleBreakpoint(MigrationInterface $migration)
{
$this->query(
sprintf(
'UPDATE %1$s SET %2$s = CASE %2$s WHEN %3$s THEN %4$s ELSE %3$s END, %7$s = %7$s WHERE %5$s = \'%6$s\';',
$this->getSchemaTableName(),
$this->quoteColumnName('breakpoint'),
$this->castToBool(true),
$this->castToBool(false),
$this->quoteColumnName('version'),
$migration->getVersion(),
$this->quoteColumnName('start_time')
)
);
return $this;
}
/**
* @inheritDoc
*/
public function resetAllBreakpoints()
{
return $this->execute(
sprintf(
'UPDATE %1$s SET %2$s = %3$s, %4$s = %4$s WHERE %2$s <> %3$s;',
$this->getSchemaTableName(),
$this->quoteColumnName('breakpoint'),
$this->castToBool(false),
$this->quoteColumnName('start_time')
)
);
}
/**
* {@inheritdoc}
*/
public function createSchema($schemaName = 'public')
{
throw new BadMethodCallException('Creating a schema is not supported');
}
/**
* {@inheritdoc}
*/
public function dropSchema($name)
{
throw new BadMethodCallException('Dropping a schema is not supported');
}
/**
* {@inheritdoc}
*/
public function getColumnTypes()
{
return [
'string',
'char',
'text',
'integer',
'biginteger',
'float',
'decimal',
'datetime',
'timestamp',
'time',
'date',
'blob',
'binary',
'varbinary',
'boolean',
'uuid',
// Geospatial data types
'geometry',
'point',
'linestring',
'polygon',
];
}
/**
* {@inheritdoc}
*/
public function castToBool($value)
{
return (bool)$value ? 1 : 0;
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/PostgresAdapter.php 0000664 0000000 0000000 00000106765 13217376123 0022276 0 ustar 00root root 0000000 0000000 connection === null) {
if (!class_exists('PDO') || !in_array('pgsql', \PDO::getAvailableDrivers(), true)) {
// @codeCoverageIgnoreStart
throw new \RuntimeException('You need to enable the PDO_Pgsql extension for Phinx to run properly.');
// @codeCoverageIgnoreEnd
}
$db = null;
$options = $this->getOptions();
// if port is specified use it, otherwise use the PostgreSQL default
if (isset($options['port'])) {
$dsn = 'pgsql:host=' . $options['host'] . ';port=' . $options['port'] . ';dbname=' . $options['name'];
} else {
$dsn = 'pgsql:host=' . $options['host'] . ';dbname=' . $options['name'];
}
try {
$db = new \PDO($dsn, $options['user'], $options['pass'], [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION]);
} catch (\PDOException $exception) {
throw new \InvalidArgumentException(sprintf(
'There was a problem connecting to the database: %s',
$exception->getMessage()
));
}
$this->setConnection($db);
}
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
$this->connection = null;
}
/**
* {@inheritdoc}
*/
public function hasTransactions()
{
return true;
}
/**
* {@inheritdoc}
*/
public function beginTransaction()
{
$this->execute('BEGIN');
}
/**
* {@inheritdoc}
*/
public function commitTransaction()
{
$this->execute('COMMIT');
}
/**
* {@inheritdoc}
*/
public function rollbackTransaction()
{
$this->execute('ROLLBACK');
}
/**
* Quotes a schema name for use in a query.
*
* @param string $schemaName Schema Name
* @return string
*/
public function quoteSchemaName($schemaName)
{
return $this->quoteColumnName($schemaName);
}
/**
* {@inheritdoc}
*/
public function quoteTableName($tableName)
{
return $this->quoteSchemaName($this->getSchemaName()) . '.' . $this->quoteColumnName($tableName);
}
/**
* {@inheritdoc}
*/
public function quoteColumnName($columnName)
{
return '"' . $columnName . '"';
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
$result = $this->getConnection()->query(
sprintf(
'SELECT *
FROM information_schema.tables
WHERE table_schema = %s
AND lower(table_name) = lower(%s)',
$this->getConnection()->quote($this->getSchemaName()),
$this->getConnection()->quote($tableName)
)
);
return $result->rowCount() === 1;
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$options = $table->getOptions();
// Add the default primary key
$columns = $table->getPendingColumns();
if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
$column = new Column();
$column->setName('id')
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = 'id';
} elseif (isset($options['id']) && is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = $options['id'];
}
// TODO - process table options like collation etc
$sql = 'CREATE TABLE ';
$sql .= $this->quoteTableName($table->getName()) . ' (';
$this->columnsWithComments = [];
foreach ($columns as $column) {
$sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
// set column comments, if needed
if ($column->getComment()) {
$this->columnsWithComments[] = $column;
}
}
// set the primary key(s)
if (isset($options['primary_key'])) {
$sql = rtrim($sql);
$sql .= sprintf(' CONSTRAINT %s_pkey PRIMARY KEY (', $table->getName());
if (is_string($options['primary_key'])) { // handle primary_key => 'id'
$sql .= $this->quoteColumnName($options['primary_key']);
} elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
$sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
}
$sql .= ')';
} else {
$sql = substr(rtrim($sql), 0, -1); // no primary keys
}
// set the foreign keys
$foreignKeys = $table->getForeignKeys();
if (!empty($foreignKeys)) {
foreach ($foreignKeys as $foreignKey) {
$sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey, $table->getName());
}
}
$sql .= ');';
// process column comments
if (!empty($this->columnsWithComments)) {
foreach ($this->columnsWithComments as $column) {
$sql .= $this->getColumnCommentSqlDefinition($column, $table->getName());
}
}
// set the indexes
$indexes = $table->getIndexes();
if (!empty($indexes)) {
foreach ($indexes as $index) {
$sql .= $this->getIndexSqlDefinition($index, $table->getName());
}
}
// execute the sql
$this->execute($sql);
// process table comments
if (isset($options['comment'])) {
$sql = sprintf(
'COMMENT ON TABLE %s IS %s',
$this->quoteTableName($table->getName()),
$this->getConnection()->quote($options['comment'])
);
$this->execute($sql);
}
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$sql = sprintf(
'ALTER TABLE %s RENAME TO %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($newTableName)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$sql = sprintf(
'TRUNCATE TABLE %s',
$this->quoteTableName($tableName)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
$columns = [];
$sql = sprintf(
"SELECT column_name, data_type, is_identity, is_nullable,
column_default, character_maximum_length, numeric_precision, numeric_scale
FROM information_schema.columns
WHERE table_name ='%s'",
$tableName
);
$columnsInfo = $this->fetchAll($sql);
foreach ($columnsInfo as $columnInfo) {
$column = new Column();
$column->setName($columnInfo['column_name'])
->setType($this->getPhinxType($columnInfo['data_type']))
->setNull($columnInfo['is_nullable'] === 'YES')
->setDefault($columnInfo['column_default'])
->setIdentity($columnInfo['is_identity'] === 'YES')
->setPrecision($columnInfo['numeric_precision'])
->setScale($columnInfo['numeric_scale']);
if (preg_match('/\bwith time zone$/', $columnInfo['data_type'])) {
$column->setTimezone(true);
}
if (isset($columnInfo['character_maximum_length'])) {
$column->setLimit($columnInfo['character_maximum_length']);
}
$columns[] = $column;
}
return $columns;
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
$sql = sprintf(
"SELECT count(*)
FROM information_schema.columns
WHERE table_schema = '%s' AND table_name = '%s' AND column_name = '%s'",
$this->getSchemaName(),
$tableName,
$columnName
);
$result = $this->fetchRow($sql);
return $result['count'] > 0;
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$sql = sprintf(
'ALTER TABLE %s ADD %s %s;',
$this->quoteTableName($table->getName()),
$this->quoteColumnName($column->getName()),
$this->getColumnSqlDefinition($column)
);
if ($column->getComment()) {
$sql .= $this->getColumnCommentSqlDefinition($column, $table->getName());
}
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$sql = sprintf(
"SELECT CASE WHEN COUNT(*) > 0 THEN 1 ELSE 0 END AS column_exists
FROM information_schema.columns
WHERE table_name ='%s' AND column_name = '%s'",
$tableName,
$columnName
);
$result = $this->fetchRow($sql);
if (!(bool)$result['column_exists']) {
throw new \InvalidArgumentException("The specified column does not exist: $columnName");
}
$this->execute(
sprintf(
'ALTER TABLE %s RENAME COLUMN %s TO %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumnName)
)
);
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
// TODO - is it possible to merge these 3 queries into less?
// change data type
$sql = sprintf(
'ALTER TABLE %s ALTER COLUMN %s TYPE %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->getColumnSqlDefinition($newColumn)
);
//NULL and DEFAULT cannot be set while changing column type
$sql = preg_replace('/ NOT NULL/', '', $sql);
$sql = preg_replace('/ NULL/', '', $sql);
//If it is set, DEFAULT is the last definition
$sql = preg_replace('/DEFAULT .*/', '', $sql);
$this->execute($sql);
// process null
$sql = sprintf(
'ALTER TABLE %s ALTER COLUMN %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName)
);
if ($newColumn->isNull()) {
$sql .= ' DROP NOT NULL';
} else {
$sql .= ' SET NOT NULL';
}
$this->execute($sql);
if (!is_null($newColumn->getDefault())) {
//change default
$this->execute(
sprintf(
'ALTER TABLE %s ALTER COLUMN %s SET %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->getDefaultValueDefinition($newColumn->getDefault())
)
);
} else {
//drop default
$this->execute(
sprintf(
'ALTER TABLE %s ALTER COLUMN %s DROP DEFAULT',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName)
)
);
}
// rename column
if ($columnName !== $newColumn->getName()) {
$this->execute(
sprintf(
'ALTER TABLE %s RENAME COLUMN %s TO %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumn->getName())
)
);
}
// change column comment if needed
if ($newColumn->getComment()) {
$sql = $this->getColumnCommentSqlDefinition($newColumn, $tableName);
$this->execute($sql);
}
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$this->execute(
sprintf(
'ALTER TABLE %s DROP COLUMN %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName)
)
);
}
/**
* Get an array of indexes from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getIndexes($tableName)
{
$indexes = [];
$sql = "SELECT
i.relname AS index_name,
a.attname AS column_name
FROM
pg_class t,
pg_class i,
pg_index ix,
pg_attribute a
WHERE
t.oid = ix.indrelid
AND i.oid = ix.indexrelid
AND a.attrelid = t.oid
AND a.attnum = ANY(ix.indkey)
AND t.relkind = 'r'
AND t.relname = '$tableName'
ORDER BY
t.relname,
i.relname;";
$rows = $this->fetchAll($sql);
foreach ($rows as $row) {
if (!isset($indexes[$row['index_name']])) {
$indexes[$row['index_name']] = ['columns' => []];
}
$indexes[$row['index_name']]['columns'][] = strtolower($row['column_name']);
}
return $indexes;
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns];
}
$columns = array_map('strtolower', $columns);
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
if (array_diff($index['columns'], $columns) === array_diff($columns, $index['columns'])) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $name => $index) {
if ($name === $indexName) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$sql = $this->getIndexSqlDefinition($index, $table->getName());
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$indexes = $this->getIndexes($tableName);
$columns = array_map('strtolower', $columns);
foreach ($indexes as $indexName => $index) {
$a = array_diff($columns, $index['columns']);
if (empty($a)) {
$this->execute(
sprintf(
'DROP INDEX IF EXISTS %s',
$this->quoteColumnName($indexName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$sql = sprintf(
'DROP INDEX IF EXISTS %s',
$indexName
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$foreignKeys = $this->getForeignKeys($tableName);
if ($constraint) {
if (isset($foreignKeys[$constraint])) {
return !empty($foreignKeys[$constraint]);
}
return false;
} else {
foreach ($foreignKeys as $key) {
$a = array_diff($columns, $key['columns']);
if (empty($a)) {
return true;
}
}
return false;
}
}
/**
* Get an array of foreign keys from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getForeignKeys($tableName)
{
$foreignKeys = [];
$rows = $this->fetchAll(sprintf(
"SELECT
tc.constraint_name,
tc.table_name, kcu.column_name,
ccu.table_name AS referenced_table_name,
ccu.column_name AS referenced_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = '%s'
ORDER BY kcu.position_in_unique_constraint",
$tableName
));
foreach ($rows as $row) {
$foreignKeys[$row['constraint_name']]['table'] = $row['table_name'];
$foreignKeys[$row['constraint_name']]['columns'][] = $row['column_name'];
$foreignKeys[$row['constraint_name']]['referenced_table'] = $row['referenced_table_name'];
$foreignKeys[$row['constraint_name']]['referenced_columns'][] = $row['referenced_column_name'];
}
return $foreignKeys;
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$sql = sprintf(
'ALTER TABLE %s ADD %s',
$this->quoteTableName($table->getName()),
$this->getForeignKeySqlDefinition($foreignKey, $table->getName())
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
if ($constraint) {
$this->execute(
sprintf(
'ALTER TABLE %s DROP CONSTRAINT %s',
$this->quoteTableName($tableName),
$constraint
)
);
} else {
foreach ($columns as $column) {
$rows = $this->fetchAll(sprintf(
"SELECT CONSTRAINT_NAME
FROM information_schema.KEY_COLUMN_USAGE
WHERE TABLE_SCHEMA = CURRENT_SCHEMA()
AND TABLE_NAME IS NOT NULL
AND TABLE_NAME = '%s'
AND COLUMN_NAME = '%s'
ORDER BY POSITION_IN_UNIQUE_CONSTRAINT",
$tableName,
$column
));
foreach ($rows as $row) {
$this->dropForeignKey($tableName, $columns, $row['constraint_name']);
}
}
}
}
/**
* {@inheritdoc}
*/
public function getSqlType($type, $limit = null)
{
switch ($type) {
case static::PHINX_TYPE_INTEGER:
if ($limit && $limit == static::INT_SMALL) {
return [
'name' => 'smallint',
'limit' => static::INT_SMALL
];
}
return ['name' => $type];
case static::PHINX_TYPE_TEXT:
case static::PHINX_TYPE_TIME:
case static::PHINX_TYPE_DATE:
case static::PHINX_TYPE_BOOLEAN:
case static::PHINX_TYPE_JSON:
case static::PHINX_TYPE_JSONB:
case static::PHINX_TYPE_UUID:
case static::PHINX_TYPE_CIDR:
case static::PHINX_TYPE_INET:
case static::PHINX_TYPE_MACADDR:
return ['name' => $type];
case static::PHINX_TYPE_DECIMAL:
return ['name' => $type, 'precision' => 18, 'scale' => 0];
case static::PHINX_TYPE_STRING:
return ['name' => 'character varying', 'limit' => 255];
case static::PHINX_TYPE_CHAR:
return ['name' => 'character', 'limit' => 255];
case static::PHINX_TYPE_BIG_INTEGER:
return ['name' => 'bigint'];
case static::PHINX_TYPE_FLOAT:
return ['name' => 'real'];
case static::PHINX_TYPE_DATETIME:
case static::PHINX_TYPE_TIMESTAMP:
return ['name' => 'timestamp'];
case static::PHINX_TYPE_BLOB:
case static::PHINX_TYPE_BINARY:
return ['name' => 'bytea'];
case static::PHINX_TYPE_INTERVAL:
return ['name' => 'interval'];
// Geospatial database types
// Spatial storage in Postgres is done via the PostGIS extension,
// which enables the use of the "geography" type in combination
// with SRID 4326.
case static::PHINX_TYPE_GEOMETRY:
return ['name' => 'geography', 'type' => 'geometry', 'srid' => 4326];
case static::PHINX_TYPE_POINT:
return ['name' => 'geography', 'type' => 'point', 'srid' => 4326];
case static::PHINX_TYPE_LINESTRING:
return ['name' => 'geography', 'type' => 'linestring', 'srid' => 4326];
case static::PHINX_TYPE_POLYGON:
return ['name' => 'geography', 'type' => 'polygon', 'srid' => 4326];
default:
if ($this->isArrayType($type)) {
return ['name' => $type];
}
// Return array type
throw new \RuntimeException('The type: "' . $type . '" is not supported');
}
}
/**
* Returns Phinx type by SQL type
*
* @param string $sqlType SQL type
* @returns string Phinx type
*/
public function getPhinxType($sqlType)
{
switch ($sqlType) {
case 'character varying':
case 'varchar':
return static::PHINX_TYPE_STRING;
case 'character':
case 'char':
return static::PHINX_TYPE_CHAR;
case 'text':
return static::PHINX_TYPE_TEXT;
case 'json':
return static::PHINX_TYPE_JSON;
case 'jsonb':
return static::PHINX_TYPE_JSONB;
case 'smallint':
return [
'name' => 'smallint',
'limit' => static::INT_SMALL
];
case 'int':
case 'int4':
case 'integer':
return static::PHINX_TYPE_INTEGER;
case 'decimal':
case 'numeric':
return static::PHINX_TYPE_DECIMAL;
case 'bigint':
case 'int8':
return static::PHINX_TYPE_BIG_INTEGER;
case 'real':
case 'float4':
return static::PHINX_TYPE_FLOAT;
case 'bytea':
return static::PHINX_TYPE_BINARY;
case 'interval':
return static::PHINX_TYPE_INTERVAL;
case 'time':
case 'timetz':
case 'time with time zone':
case 'time without time zone':
return static::PHINX_TYPE_TIME;
case 'date':
return static::PHINX_TYPE_DATE;
case 'timestamp':
case 'timestamptz':
case 'timestamp with time zone':
case 'timestamp without time zone':
return static::PHINX_TYPE_DATETIME;
case 'bool':
case 'boolean':
return static::PHINX_TYPE_BOOLEAN;
case 'uuid':
return static::PHINX_TYPE_UUID;
case 'cidr':
return static::PHINX_TYPE_CIDR;
case 'inet':
return static::PHINX_TYPE_INET;
case 'macaddr':
return static::PHINX_TYPE_MACADDR;
default:
throw new \RuntimeException('The PostgreSQL type: "' . $sqlType . '" is not supported');
}
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
$charset = isset($options['charset']) ? $options['charset'] : 'utf8';
$this->execute(sprintf("CREATE DATABASE %s WITH ENCODING = '%s'", $name, $charset));
}
/**
* {@inheritdoc}
*/
public function hasDatabase($databaseName)
{
$sql = sprintf("SELECT count(*) FROM pg_database WHERE datname = '%s'", $databaseName);
$result = $this->fetchRow($sql);
return $result['count'] > 0;
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$this->disconnect();
$this->execute(sprintf('DROP DATABASE IF EXISTS %s', $name));
$this->connect();
}
/**
* Get the defintion for a `DEFAULT` statement.
*
* @param mixed $default
* @return string
*/
protected function getDefaultValueDefinition($default)
{
if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
$default = $this->getConnection()->quote($default);
} elseif (is_bool($default)) {
$default = $this->castToBool($default);
}
return isset($default) ? 'DEFAULT ' . $default : '';
}
/**
* Gets the PostgreSQL Column Definition for a Column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @return string
*/
protected function getColumnSqlDefinition(Column $column)
{
$buffer = [];
if ($column->isIdentity()) {
$buffer[] = $column->getType() == 'biginteger' ? 'BIGSERIAL' : 'SERIAL';
} else {
$sqlType = $this->getSqlType($column->getType(), $column->getLimit());
$buffer[] = strtoupper($sqlType['name']);
// integers cant have limits in postgres
if (static::PHINX_TYPE_DECIMAL === $sqlType['name'] && ($column->getPrecision() || $column->getScale())) {
$buffer[] = sprintf(
'(%s, %s)',
$column->getPrecision() ?: $sqlType['precision'],
$column->getScale() ?: $sqlType['scale']
);
} elseif (in_array($sqlType['name'], ['geography'])) {
// geography type must be written with geometry type and srid, like this: geography(POLYGON,4326)
$buffer[] = sprintf(
'(%s,%s)',
strtoupper($sqlType['type']),
$sqlType['srid']
);
} elseif (!in_array($sqlType['name'], ['integer', 'smallint', 'bigint'])) {
if ($column->getLimit() || isset($sqlType['limit'])) {
$buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']);
}
}
$timeTypes = [
'time',
'timestamp',
];
if (in_array($sqlType['name'], $timeTypes) && $column->isTimezone()) {
$buffer[] = strtoupper('with time zone');
}
}
$buffer[] = $column->isNull() ? 'NULL' : 'NOT NULL';
if (!is_null($column->getDefault())) {
$buffer[] = $this->getDefaultValueDefinition($column->getDefault());
}
return implode(' ', $buffer);
}
/**
* Gets the PostgreSQL Column Comment Defininition for a column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @param string $tableName Table name
* @return string
*/
protected function getColumnCommentSqlDefinition(Column $column, $tableName)
{
// passing 'null' is to remove column comment
$comment = (strcasecmp($column->getComment(), 'NULL') !== 0)
? $this->getConnection()->quote($column->getComment())
: 'NULL';
return sprintf(
'COMMENT ON COLUMN %s.%s IS %s;',
$this->quoteSchemaName($tableName),
$this->quoteColumnName($column->getName()),
$comment
);
}
/**
* Gets the PostgreSQL Index Definition for an Index object.
*
* @param \Phinx\Db\Table\Index $index Index
* @param string $tableName Table name
* @return string
*/
protected function getIndexSqlDefinition(Index $index, $tableName)
{
if (is_string($index->getName())) {
$indexName = $index->getName();
} else {
$columnNames = $index->getColumns();
if (is_string($columnNames)) {
$columnNames = [$columnNames];
}
$indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames));
}
$def = sprintf(
"CREATE %s INDEX %s ON %s (%s);",
($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''),
$indexName,
$this->quoteTableName($tableName),
implode(',', array_map([$this, 'quoteColumnName'], $index->getColumns()))
);
return $def;
}
/**
* Gets the MySQL Foreign Key Definition for an ForeignKey object.
*
* @param \Phinx\Db\Table\ForeignKey $foreignKey
* @param string $tableName Table name
* @return string
*/
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $tableName)
{
$constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns());
$def = ' CONSTRAINT "' . $constraintName . '" FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")';
$def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} (\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")';
if ($foreignKey->getOnDelete()) {
$def .= " ON DELETE {$foreignKey->getOnDelete()}";
}
if ($foreignKey->getOnUpdate()) {
$def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
}
return $def;
}
/**
* {@inheritdoc}
*/
public function createSchemaTable()
{
// Create the public/custom schema if it doesn't already exist
if ($this->hasSchema($this->getSchemaName()) === false) {
$this->createSchema($this->getSchemaName());
}
$this->fetchAll(sprintf('SET search_path TO %s', $this->getSchemaName()));
parent::createSchemaTable();
}
/**
* Creates the specified schema.
*
* @param string $schemaName Schema Name
* @return void
*/
public function createSchema($schemaName = 'public')
{
$sql = sprintf('CREATE SCHEMA %s;', $this->quoteSchemaName($schemaName)); // from postgres 9.3 we can use "CREATE SCHEMA IF NOT EXISTS schema_name"
$this->execute($sql);
}
/**
* Checks to see if a schema exists.
*
* @param string $schemaName Schema Name
* @return bool
*/
public function hasSchema($schemaName)
{
$sql = sprintf(
"SELECT count(*)
FROM pg_namespace
WHERE nspname = '%s'",
$schemaName
);
$result = $this->fetchRow($sql);
return $result['count'] > 0;
}
/**
* Drops the specified schema table.
*
* @param string $schemaName Schema name
* @return void
*/
public function dropSchema($schemaName)
{
$sql = sprintf("DROP SCHEMA IF EXISTS %s CASCADE;", $this->quoteSchemaName($schemaName));
$this->execute($sql);
}
/**
* Drops all schemas.
*
* @return void
*/
public function dropAllSchemas()
{
foreach ($this->getAllSchemas() as $schema) {
$this->dropSchema($schema);
}
}
/**
* Returns schemas.
*
* @return array
*/
public function getAllSchemas()
{
$sql = "SELECT schema_name
FROM information_schema.schemata
WHERE schema_name <> 'information_schema' AND schema_name !~ '^pg_'";
$items = $this->fetchAll($sql);
$schemaNames = [];
foreach ($items as $item) {
$schemaNames[] = $item['schema_name'];
}
return $schemaNames;
}
/**
* {@inheritdoc}
*/
public function getColumnTypes()
{
return array_merge(parent::getColumnTypes(), ['json', 'jsonb', 'cidr', 'inet', 'macaddr', 'interval']);
}
/**
* {@inheritdoc}
*/
public function isValidColumnType(Column $column)
{
// If not a standard column type, maybe it is array type?
return (parent::isValidColumnType($column) || $this->isArrayType($column->getType()));
}
/**
* Check if the given column is an array of a valid type.
*
* @param string $columnType
* @return bool
*/
protected function isArrayType($columnType)
{
if (!preg_match('/^([a-z]+)(?:\[\]){1,}$/', $columnType, $matches)) {
return false;
}
$baseType = $matches[1];
return in_array($baseType, $this->getColumnTypes());
}
/**
* Gets the schema name.
*
* @return string
*/
private function getSchemaName()
{
$options = $this->getOptions();
return empty($options['schema']) ? 'public' : $options['schema'];
}
/**
* {@inheritdoc}
*/
public function castToBool($value)
{
return (bool)$value ? 'TRUE' : 'FALSE';
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/ProxyAdapter.php 0000664 0000000 0000000 00000020750 13217376123 0021576 0 ustar 00root root 0000000 0000000
*/
class ProxyAdapter extends AdapterWrapper
{
/**
* @var array
*/
protected $commands;
/**
* {@inheritdoc}
*/
public function getAdapterType()
{
return 'ProxyAdapter';
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$this->recordCommand('createTable', [$table->getName()]);
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$this->recordCommand('renameTable', [$tableName, $newTableName]);
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->recordCommand('dropTable', [$tableName]);
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$this->recordCommand('truncateTable', [$tableName]);
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$this->recordCommand('addColumn', [$table, $column]);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$this->recordCommand('renameColumn', [$tableName, $columnName, $newColumnName]);
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
$this->recordCommand('changeColumn', [$tableName, $columnName, $newColumn]);
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$this->recordCommand('dropColumn', [$tableName, $columnName]);
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$this->recordCommand('addIndex', [$table, $index]);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns, $options = [])
{
$this->recordCommand('dropIndex', [$tableName, $columns, $options]);
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$this->recordCommand('dropIndexByName', [$tableName, $indexName]);
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$this->recordCommand('addForeignKey', [$table, $foreignKey]);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
$this->recordCommand('dropForeignKey', [$columns, $constraint]);
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
$this->recordCommand('createDatabase', [$name, $options]);
}
/**
* Record a command for execution later.
*
* @param string $name Command Name
* @param array $arguments Command Arguments
* @return void
*/
public function recordCommand($name, $arguments)
{
$this->commands[] = [
'name' => $name,
'arguments' => $arguments
];
}
/**
* Sets an array of recorded commands.
*
* @param array $commands Commands
* @return \Phinx\Db\Adapter\ProxyAdapter
*/
public function setCommands($commands)
{
$this->commands = $commands;
return $this;
}
/**
* Gets an array of the recorded commands.
*
* @return array
*/
public function getCommands()
{
return $this->commands;
}
/**
* Gets an array of the recorded commands in reverse.
*
* @throws \Phinx\Migration\IrreversibleMigrationException if a command cannot be reversed.
* @return array
*/
public function getInvertedCommands()
{
if ($this->getCommands() === null) {
return [];
}
$invCommands = [];
$supportedCommands = [
'createTable', 'renameTable', 'addColumn',
'renameColumn', 'addIndex', 'addForeignKey'
];
foreach (array_reverse($this->getCommands()) as $command) {
if (!in_array($command['name'], $supportedCommands)) {
throw new IrreversibleMigrationException(sprintf(
'Cannot reverse a "%s" command',
$command['name']
));
}
$invertMethod = 'invert' . ucfirst($command['name']);
$invertedCommand = $this->$invertMethod($command['arguments']);
$invCommands[] = [
'name' => $invertedCommand['name'],
'arguments' => $invertedCommand['arguments']
];
}
return $invCommands;
}
/**
* Execute the recorded commands.
*
* @return void
*/
public function executeCommands()
{
$commands = $this->getCommands();
foreach ($commands as $command) {
call_user_func_array([$this->getAdapter(), $command['name']], $command['arguments']);
}
}
/**
* Execute the recorded commands in reverse.
*
* @return void
*/
public function executeInvertedCommands()
{
$commands = $this->getInvertedCommands();
foreach ($commands as $command) {
call_user_func_array([$this->getAdapter(), $command['name']], $command['arguments']);
}
}
/**
* Returns the reverse of a createTable command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertCreateTable($args)
{
return ['name' => 'dropTable', 'arguments' => [$args[0]]];
}
/**
* Returns the reverse of a renameTable command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertRenameTable($args)
{
return ['name' => 'renameTable', 'arguments' => [$args[1], $args[0]]];
}
/**
* Returns the reverse of a addColumn command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertAddColumn($args)
{
return ['name' => 'dropColumn', 'arguments' => [$args[0]->getName(), $args[1]->getName()]];
}
/**
* Returns the reverse of a renameColumn command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertRenameColumn($args)
{
return ['name' => 'renameColumn', 'arguments' => [$args[0], $args[2], $args[1]]];
}
/**
* Returns the reverse of a addIndex command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertAddIndex($args)
{
return ['name' => 'dropIndex', 'arguments' => [$args[0]->getName(), $args[1]->getColumns()]];
}
/**
* Returns the reverse of a addForeignKey command.
*
* @param array $args Method Arguments
* @return array
*/
public function invertAddForeignKey($args)
{
return ['name' => 'dropForeignKey', 'arguments' => [$args[0]->getName(), $args[1]->getColumns()]];
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/SQLiteAdapter.php 0000664 0000000 0000000 00000077673 13217376123 0021636 0 ustar 00root root 0000000 0000000
* @author Richard McIntyre
*/
class SQLiteAdapter extends PdoAdapter implements AdapterInterface
{
protected $definitionsWithLimits = [
'CHARACTER',
'VARCHAR',
'VARYING CHARACTER',
'NCHAR',
'NATIVE CHARACTER',
'NVARCHAR'
];
/**
* {@inheritdoc}
*/
public function connect()
{
if ($this->connection === null) {
if (!class_exists('PDO') || !in_array('sqlite', \PDO::getAvailableDrivers(), true)) {
// @codeCoverageIgnoreStart
throw new \RuntimeException('You need to enable the PDO_SQLITE extension for Phinx to run properly.');
// @codeCoverageIgnoreEnd
}
$db = null;
$options = $this->getOptions();
// if port is specified use it, otherwise use the MySQL default
if (isset($options['memory'])) {
$dsn = 'sqlite::memory:';
} else {
$dsn = 'sqlite:' . $options['name'];
if (file_exists($options['name'] . '.sqlite3')) {
$dsn = 'sqlite:' . $options['name'] . '.sqlite3';
}
}
try {
$db = new \PDO($dsn);
} catch (\PDOException $exception) {
throw new \InvalidArgumentException(sprintf(
'There was a problem connecting to the database: %s',
$exception->getMessage()
));
}
$this->setConnection($db);
}
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
$this->connection = null;
}
/**
* {@inheritdoc}
*/
public function hasTransactions()
{
return true;
}
/**
* {@inheritdoc}
*/
public function beginTransaction()
{
$this->execute('BEGIN TRANSACTION');
}
/**
* {@inheritdoc}
*/
public function commitTransaction()
{
$this->execute('COMMIT');
}
/**
* {@inheritdoc}
*/
public function rollbackTransaction()
{
$this->execute('ROLLBACK');
}
/**
* {@inheritdoc}
*/
public function quoteTableName($tableName)
{
return str_replace('.', '`.`', $this->quoteColumnName($tableName));
}
/**
* {@inheritdoc}
*/
public function quoteColumnName($columnName)
{
return '`' . str_replace('`', '``', $columnName) . '`';
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
$tables = [];
$rows = $this->fetchAll(sprintf('SELECT name FROM sqlite_master WHERE type=\'table\' AND name=\'%s\'', $tableName));
foreach ($rows as $row) {
$tables[] = strtolower($row[0]);
}
return in_array(strtolower($tableName), $tables);
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
// Add the default primary key
$columns = $table->getPendingColumns();
$options = $table->getOptions();
if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
$column = new Column();
$column->setName('id')
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
} elseif (isset($options['id']) && is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
}
$sql = 'CREATE TABLE ';
$sql .= $this->quoteTableName($table->getName()) . ' (';
foreach ($columns as $column) {
$sql .= $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column) . ', ';
}
// set the primary key(s)
if (isset($options['primary_key'])) {
$sql = rtrim($sql);
$sql .= ' PRIMARY KEY (';
if (is_string($options['primary_key'])) { // handle primary_key => 'id'
$sql .= $this->quoteColumnName($options['primary_key']);
} elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
$sql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
}
$sql .= ')';
} else {
$sql = substr(rtrim($sql), 0, -1); // no primary keys
}
// set the foreign keys
$foreignKeys = $table->getForeignKeys();
if (!empty($foreignKeys)) {
foreach ($foreignKeys as $foreignKey) {
$sql .= ', ' . $this->getForeignKeySqlDefinition($foreignKey);
}
}
$sql = rtrim($sql) . ');';
// execute the sql
$this->execute($sql);
foreach ($table->getIndexes() as $index) {
$this->addIndex($table, $index);
}
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $this->quoteTableName($tableName), $this->quoteTableName($newTableName)));
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$sql = sprintf(
'DELETE FROM %s',
$this->quoteTableName($tableName)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
$columns = [];
$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
foreach ($rows as $columnInfo) {
$column = new Column();
$type = strtolower($columnInfo['type']);
$column->setName($columnInfo['name'])
->setNull($columnInfo['notnull'] !== '1')
->setDefault($columnInfo['dflt_value']);
$phinxType = $this->getPhinxType($type);
$column->setType($phinxType['name'])
->setLimit($phinxType['limit']);
if ($columnInfo['pk'] == 1) {
$column->setIdentity(true);
}
$columns[] = $column;
}
return $columns;
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
foreach ($rows as $column) {
if (strcasecmp($column['name'], $columnName) === 0) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$sql = sprintf(
'ALTER TABLE %s ADD COLUMN %s %s',
$this->quoteTableName($table->getName()),
$this->quoteColumnName($column->getName()),
$this->getColumnSqlDefinition($column)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$tmpTableName = 'tmp_' . $tableName;
$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
$sql = '';
foreach ($rows as $table) {
if ($table['tbl_name'] === $tableName) {
$sql = $table['sql'];
}
}
$columns = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
$selectColumns = [];
$writeColumns = [];
foreach ($columns as $column) {
$selectName = $column['name'];
$writeName = ($selectName == $columnName)? $newColumnName : $selectName;
$selectColumns[] = $this->quoteColumnName($selectName);
$writeColumns[] = $this->quoteColumnName($writeName);
}
if (!in_array($this->quoteColumnName($columnName), $selectColumns)) {
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: ' . $columnName
));
}
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $tableName, $tmpTableName));
$sql = str_replace(
$this->quoteColumnName($columnName),
$this->quoteColumnName($newColumnName),
$sql
);
$this->execute($sql);
$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$tableName,
implode(', ', $writeColumns),
implode(', ', $selectColumns),
$tmpTableName
);
$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
// TODO: DRY this up....
$tmpTableName = 'tmp_' . $tableName;
$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
$sql = '';
foreach ($rows as $table) {
if ($table['tbl_name'] === $tableName) {
$sql = $table['sql'];
}
}
$columns = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
$selectColumns = [];
$writeColumns = [];
foreach ($columns as $column) {
$selectName = $column['name'];
$writeName = ($selectName === $columnName)? $newColumn->getName() : $selectName;
$selectColumns[] = $this->quoteColumnName($selectName);
$writeColumns[] = $this->quoteColumnName($writeName);
}
if (!in_array($this->quoteColumnName($columnName), $selectColumns)) {
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: ' . $columnName
));
}
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $tableName, $tmpTableName));
$sql = preg_replace(
sprintf("/%s(?:\/\*.*?\*\/|\([^)]+\)|'[^']*?'|[^,])+([,)])/", $this->quoteColumnName($columnName)),
sprintf('%s %s$1', $this->quoteColumnName($newColumn->getName()), $this->getColumnSqlDefinition($newColumn)),
$sql,
1
);
$this->execute($sql);
$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$tableName,
implode(', ', $writeColumns),
implode(', ', $selectColumns),
$tmpTableName
);
$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
// TODO: DRY this up....
$tmpTableName = 'tmp_' . $tableName;
$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
$sql = '';
foreach ($rows as $table) {
if ($table['tbl_name'] === $tableName) {
$sql = $table['sql'];
}
}
$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
$columns = [];
$columnType = null;
foreach ($rows as $row) {
if ($row['name'] !== $columnName) {
$columns[] = $row['name'];
} else {
$found = true;
$columnType = $row['type'];
}
}
if (!isset($found)) {
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: ' . $columnName
));
}
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $tableName, $tmpTableName));
$sql = preg_replace(
sprintf("/%s\s%s.*(,\s(?!')|\)$)/U", preg_quote($this->quoteColumnName($columnName)), preg_quote($columnType)),
"",
$sql
);
if (substr($sql, -2) === ', ') {
$sql = substr($sql, 0, -2) . ')';
}
$this->execute($sql);
$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$tableName,
implode(', ', $columns),
implode(', ', $columns),
$tmpTableName
);
$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
}
/**
* Get an array of indexes from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getIndexes($tableName)
{
$indexes = [];
$rows = $this->fetchAll(sprintf('pragma index_list(%s)', $tableName));
foreach ($rows as $row) {
$indexData = $this->fetchAll(sprintf('pragma index_info(%s)', $row['name']));
if (!isset($indexes[$tableName])) {
$indexes[$tableName] = ['index' => $row['name'], 'columns' => []];
}
foreach ($indexData as $indexItem) {
$indexes[$tableName]['columns'][] = strtolower($indexItem['name']);
}
}
return $indexes;
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$columns = array_map('strtolower', $columns);
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
$a = array_diff($columns, $index['columns']);
if (empty($a)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
if ($indexName === $index['index']) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$indexColumnArray = [];
foreach ($index->getColumns() as $column) {
$indexColumnArray[] = sprintf('`%s` ASC', $column);
}
$indexColumns = implode(',', $indexColumnArray);
$this->execute(
sprintf(
'CREATE %s ON %s (%s)',
$this->getIndexSqlDefinition($table, $index),
$this->quoteTableName($table->getName()),
$indexColumns
)
);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$indexes = $this->getIndexes($tableName);
$columns = array_map('strtolower', $columns);
foreach ($indexes as $index) {
$a = array_diff($columns, $index['columns']);
if (empty($a)) {
$this->execute(
sprintf(
'DROP INDEX %s',
$this->quoteColumnName($index['index'])
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
if ($indexName === $index['index']) {
$this->execute(
sprintf(
'DROP INDEX %s',
$this->quoteColumnName($indexName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$foreignKeys = $this->getForeignKeys($tableName);
$a = array_diff($columns, $foreignKeys);
if (empty($a)) {
return true;
}
return false;
}
/**
* Get an array of foreign keys from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getForeignKeys($tableName)
{
$foreignKeys = [];
$rows = $this->fetchAll(
"SELECT sql, tbl_name
FROM (
SELECT sql sql, type type, tbl_name tbl_name, name name
FROM sqlite_master
UNION ALL
SELECT sql, type, tbl_name, name
FROM sqlite_temp_master
)
WHERE type != 'meta'
AND sql NOTNULL
AND name NOT LIKE 'sqlite_%'
ORDER BY substr(type, 2, 1), name"
);
foreach ($rows as $row) {
if ($row['tbl_name'] === $tableName) {
if (strpos($row['sql'], 'REFERENCES') !== false) {
preg_match_all("/\(`([^`]*)`\) REFERENCES/", $row['sql'], $matches);
foreach ($matches[1] as $match) {
$foreignKeys[] = $match;
}
}
}
}
return $foreignKeys;
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
// TODO: DRY this up....
$this->execute('pragma foreign_keys = ON');
$tmpTableName = 'tmp_' . $table->getName();
$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
$sql = '';
foreach ($rows as $row) {
if ($row['tbl_name'] === $table->getName()) {
$sql = $row['sql'];
}
}
$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($table->getName())));
$columns = [];
foreach ($rows as $column) {
$columns[] = $this->quoteColumnName($column['name']);
}
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $this->quoteTableName($table->getName()), $tmpTableName));
$sql = substr($sql, 0, -1) . ',' . $this->getForeignKeySqlDefinition($foreignKey) . ')';
$this->execute($sql);
$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$this->quoteTableName($table->getName()),
implode(', ', $columns),
implode(', ', $columns),
$this->quoteTableName($tmpTableName)
);
$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
// TODO: DRY this up....
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$tmpTableName = 'tmp_' . $tableName;
$rows = $this->fetchAll('select * from sqlite_master where `type` = \'table\'');
$sql = '';
foreach ($rows as $table) {
if ($table['tbl_name'] === $tableName) {
$sql = $table['sql'];
}
}
$rows = $this->fetchAll(sprintf('pragma table_info(%s)', $this->quoteTableName($tableName)));
$replaceColumns = [];
foreach ($rows as $row) {
if (!in_array($row['name'], $columns)) {
$replaceColumns[] = $row['name'];
} else {
$found = true;
}
}
if (!isset($found)) {
throw new \InvalidArgumentException(sprintf(
'The specified column doesn\'t exist: '
));
}
$this->execute(sprintf('ALTER TABLE %s RENAME TO %s', $this->quoteTableName($tableName), $tmpTableName));
foreach ($columns as $columnName) {
$search = sprintf(
"/,[^,]*\(%s(?:,`?(.*)`?)?\) REFERENCES[^,]*\([^\)]*\)[^,)]*/",
$this->quoteColumnName($columnName)
);
$sql = preg_replace($search, '', $sql, 1);
}
$this->execute($sql);
$sql = sprintf(
'INSERT INTO %s(%s) SELECT %s FROM %s',
$tableName,
implode(', ', $columns),
implode(', ', $columns),
$tmpTableName
);
$this->execute($sql);
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tmpTableName)));
}
/**
* {@inheritdoc}
*/
public function insert(Table $table, $row)
{
$sql = sprintf(
"INSERT INTO %s ",
$this->quoteTableName($table->getName())
);
$columns = array_keys($row);
$sql .= "(" . implode(', ', array_map([$this, 'quoteColumnName'], $columns)) . ")";
$sql .= " VALUES ";
$sql .= "(" . implode(', ', array_map(function ($value) {
if (is_numeric($value)) {
return $value;
}
if ($value === null) {
return 'null';
}
return $this->getConnection()->quote($value);
}, $row)) . ")";
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function getSqlType($type, $limit = null)
{
switch ($type) {
case static::PHINX_TYPE_STRING:
return ['name' => 'varchar', 'limit' => 255];
case static::PHINX_TYPE_CHAR:
return ['name' => 'char', 'limit' => 255];
case static::PHINX_TYPE_TEXT:
return ['name' => 'text'];
case static::PHINX_TYPE_INTEGER:
return ['name' => 'integer'];
case static::PHINX_TYPE_BIG_INTEGER:
return ['name' => 'bigint'];
case static::PHINX_TYPE_FLOAT:
return ['name' => 'float'];
case static::PHINX_TYPE_DECIMAL:
return ['name' => 'decimal'];
case static::PHINX_TYPE_DATETIME:
return ['name' => 'datetime'];
case static::PHINX_TYPE_TIMESTAMP:
return ['name' => 'datetime'];
case static::PHINX_TYPE_TIME:
return ['name' => 'time'];
case static::PHINX_TYPE_DATE:
return ['name' => 'date'];
case static::PHINX_TYPE_BLOB:
case static::PHINX_TYPE_BINARY:
return ['name' => 'blob'];
case static::PHINX_TYPE_BOOLEAN:
return ['name' => 'boolean'];
case static::PHINX_TYPE_UUID:
return ['name' => 'char', 'limit' => 36];
case static::PHINX_TYPE_ENUM:
return ['name' => 'enum'];
// Geospatial database types
// No specific data types exist in SQLite, instead all geospatial
// functionality is handled in the client. See also: SpatiaLite.
case static::PHINX_TYPE_GEOMETRY:
case static::PHINX_TYPE_POLYGON:
return ['name' => 'text'];
case static::PHINX_TYPE_LINESTRING:
return ['name' => 'varchar', 'limit' => 255];
case static::PHINX_TYPE_POINT:
return ['name' => 'float'];
default:
throw new \RuntimeException('The type: "' . $type . '" is not supported.');
}
}
/**
* Returns Phinx type by SQL type
*
* @param string $sqlTypeDef SQL type
* @returns string Phinx type
*/
public function getPhinxType($sqlTypeDef)
{
if (!preg_match('/^([\w]+)(\(([\d]+)*(,([\d]+))*\))*$/', $sqlTypeDef, $matches)) {
throw new \RuntimeException('Column type ' . $sqlTypeDef . ' is not supported');
} else {
$limit = null;
$precision = null;
$type = $matches[1];
if (count($matches) > 2) {
$limit = $matches[3] ?: null;
}
if (count($matches) > 4) {
$precision = $matches[5];
}
switch ($matches[1]) {
case 'varchar':
$type = static::PHINX_TYPE_STRING;
if ($limit === 255) {
$limit = null;
}
break;
case 'char':
$type = static::PHINX_TYPE_CHAR;
if ($limit === 255) {
$limit = null;
}
if ($limit === 36) {
$type = static::PHINX_TYPE_UUID;
}
break;
case 'int':
$type = static::PHINX_TYPE_INTEGER;
if ($limit === 11) {
$limit = null;
}
break;
case 'bigint':
if ($limit === 11) {
$limit = null;
}
$type = static::PHINX_TYPE_BIG_INTEGER;
break;
case 'blob':
$type = static::PHINX_TYPE_BINARY;
break;
}
if ($type === 'tinyint') {
if ($matches[3] === 1) {
$type = static::PHINX_TYPE_BOOLEAN;
$limit = null;
}
}
$this->getSqlType($type);
return [
'name' => $type,
'limit' => $limit,
'precision' => $precision
];
}
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
touch($name . '.sqlite3');
}
/**
* {@inheritdoc}
*/
public function hasDatabase($name)
{
return is_file($name . '.sqlite3');
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
if (file_exists($name . '.sqlite3')) {
unlink($name . '.sqlite3');
}
}
/**
* Get the definition for a `DEFAULT` statement.
*
* @param mixed $default
* @return string
*/
protected function getDefaultValueDefinition($default)
{
if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
$default = $this->getConnection()->quote($default);
} elseif (is_bool($default)) {
$default = $this->castToBool($default);
}
return isset($default) ? ' DEFAULT ' . $default : '';
}
/**
* Gets the SQLite Column Definition for a Column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @return string
*/
protected function getColumnSqlDefinition(Column $column)
{
$sqlType = $this->getSqlType($column->getType());
$def = '';
$def .= strtoupper($sqlType['name']);
if ($column->getPrecision() && $column->getScale()) {
$def .= '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
}
$limitable = in_array(strtoupper($sqlType['name']), $this->definitionsWithLimits);
if (($column->getLimit() || isset($sqlType['limit'])) && $limitable) {
$def .= '(' . ($column->getLimit() ?: $sqlType['limit']) . ')';
}
if (($values = $column->getValues()) && is_array($values)) {
$def .= " CHECK({$column->getName()} IN ('" . implode("', '", $values) . "'))";
}
$default = $column->getDefault();
$def .= ($column->isNull() || is_null($default)) ? ' NULL' : ' NOT NULL';
$def .= $this->getDefaultValueDefinition($default);
$def .= ($column->isIdentity()) ? ' PRIMARY KEY AUTOINCREMENT' : '';
if ($column->getUpdate()) {
$def .= ' ON UPDATE ' . $column->getUpdate();
}
$def .= $this->getCommentDefinition($column);
return $def;
}
/**
* Gets the comment Definition for a Column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @return string
*/
protected function getCommentDefinition(Column $column)
{
if ($column->getComment()) {
return ' /* ' . $column->getComment() . ' */ ';
}
return '';
}
/**
* Gets the SQLite Index Definition for an Index object.
*
* @param \Phinx\Db\Table $table Table
* @param \Phinx\Db\Table\Index $index Index
* @return string
*/
protected function getIndexSqlDefinition(Table $table, Index $index)
{
if ($index->getType() === Index::UNIQUE) {
$def = 'UNIQUE INDEX';
} else {
$def = 'INDEX';
}
if (is_string($index->getName())) {
$indexName = $index->getName();
} else {
$indexName = $table->getName() . '_';
foreach ($index->getColumns() as $column) {
$indexName .= $column . '_';
}
$indexName .= 'index';
}
$def .= ' `' . $indexName . '`';
return $def;
}
/**
* {@inheritdoc}
*/
public function getColumnTypes()
{
return array_merge(parent::getColumnTypes(), ['enum']);
}
/**
* Gets the SQLite Foreign Key Definition for an ForeignKey object.
*
* @param \Phinx\Db\Table\ForeignKey $foreignKey
* @return string
*/
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey)
{
$def = '';
if ($foreignKey->getConstraint()) {
$def .= ' CONSTRAINT ' . $this->quoteColumnName($foreignKey->getConstraint());
} else {
$columnNames = [];
foreach ($foreignKey->getColumns() as $column) {
$columnNames[] = $this->quoteColumnName($column);
}
$def .= ' FOREIGN KEY (' . implode(',', $columnNames) . ')';
$refColumnNames = [];
foreach ($foreignKey->getReferencedColumns() as $column) {
$refColumnNames[] = $this->quoteColumnName($column);
}
$def .= ' REFERENCES ' . $this->quoteTableName($foreignKey->getReferencedTable()->getName()) . ' (' . implode(',', $refColumnNames) . ')';
if ($foreignKey->getOnDelete()) {
$def .= ' ON DELETE ' . $foreignKey->getOnDelete();
}
if ($foreignKey->getOnUpdate()) {
$def .= ' ON UPDATE ' . $foreignKey->getOnUpdate();
}
}
return $def;
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/SqlServerAdapter.php 0000664 0000000 0000000 00000105602 13217376123 0022403 0 ustar 00root root 0000000 0000000
*/
class SqlServerAdapter extends PdoAdapter implements AdapterInterface
{
protected $schema = 'dbo';
protected $signedColumnTypes = ['integer' => true, 'biginteger' => true, 'float' => true, 'decimal' => true];
/**
* {@inheritdoc}
*/
public function connect()
{
if ($this->connection === null) {
if (!class_exists('PDO') || !in_array('sqlsrv', \PDO::getAvailableDrivers(), true)) {
// try our connection via freetds (Mac/Linux)
$this->connectDblib();
return;
}
$db = null;
$options = $this->getOptions();
// if port is specified use it, otherwise use the SqlServer default
if (empty($options['port'])) {
$dsn = 'sqlsrv:server=' . $options['host'] . ';database=' . $options['name'];
} else {
$dsn = 'sqlsrv:server=' . $options['host'] . ',' . $options['port'] . ';database=' . $options['name'];
}
$dsn .= ';MultipleActiveResultSets=false';
$driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
// charset support
if (isset($options['charset'])) {
$driverOptions[\PDO::SQLSRV_ATTR_ENCODING] = $options['charset'];
}
// support arbitrary \PDO::SQLSRV_ATTR_* driver options and pass them to PDO
// http://php.net/manual/en/ref.pdo-sqlsrv.php#pdo-sqlsrv.constants
foreach ($options as $key => $option) {
if (strpos($key, 'sqlsrv_attr_') === 0) {
$driverOptions[constant('\PDO::' . strtoupper($key))] = $option;
}
}
try {
$db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
} catch (\PDOException $exception) {
throw new \InvalidArgumentException(sprintf(
'There was a problem connecting to the database: %s',
$exception->getMessage()
));
}
$this->setConnection($db);
}
}
/**
* Connect to MSSQL using dblib/freetds.
*
* The "sqlsrv" driver is not available on Unix machines.
*
* @throws \InvalidArgumentException
*/
protected function connectDblib()
{
if (!class_exists('PDO') || !in_array('dblib', \PDO::getAvailableDrivers(), true)) {
// @codeCoverageIgnoreStart
throw new \RuntimeException('You need to enable the PDO_Dblib extension for Phinx to run properly.');
// @codeCoverageIgnoreEnd
}
$options = $this->getOptions();
// if port is specified use it, otherwise use the SqlServer default
if (empty($options['port'])) {
$dsn = 'dblib:host=' . $options['host'] . ';dbname=' . $options['name'];
} else {
$dsn = 'dblib:host=' . $options['host'] . ':' . $options['port'] . ';dbname=' . $options['name'];
}
$driverOptions = [\PDO::ATTR_ERRMODE => \PDO::ERRMODE_EXCEPTION];
try {
$db = new \PDO($dsn, $options['user'], $options['pass'], $driverOptions);
} catch (\PDOException $exception) {
throw new \InvalidArgumentException(sprintf(
'There was a problem connecting to the database: %s',
$exception->getMessage()
));
}
$this->setConnection($db);
}
/**
* {@inheritdoc}
*/
public function disconnect()
{
$this->connection = null;
}
/**
* {@inheritdoc}
*/
public function hasTransactions()
{
return true;
}
/**
* {@inheritdoc}
*/
public function beginTransaction()
{
$this->execute('BEGIN TRANSACTION');
}
/**
* {@inheritdoc}
*/
public function commitTransaction()
{
$this->execute('COMMIT TRANSACTION');
}
/**
* {@inheritdoc}
*/
public function rollbackTransaction()
{
$this->execute('ROLLBACK TRANSACTION');
}
/**
* {@inheritdoc}
*/
public function quoteTableName($tableName)
{
return str_replace('.', '].[', $this->quoteColumnName($tableName));
}
/**
* {@inheritdoc}
*/
public function quoteColumnName($columnName)
{
return '[' . str_replace(']', '\]', $columnName) . ']';
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
$result = $this->fetchRow(sprintf('SELECT count(*) as [count] FROM information_schema.tables WHERE table_name = \'%s\';', $tableName));
return $result['count'] > 0;
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$options = $table->getOptions();
// Add the default primary key
$columns = $table->getPendingColumns();
if (!isset($options['id']) || (isset($options['id']) && $options['id'] === true)) {
$column = new Column();
$column->setName('id')
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = 'id';
} elseif (isset($options['id']) && is_string($options['id'])) {
// Handle id => "field_name" to support AUTO_INCREMENT
$column = new Column();
$column->setName($options['id'])
->setType('integer')
->setIdentity(true);
array_unshift($columns, $column);
$options['primary_key'] = $options['id'];
}
$sql = 'CREATE TABLE ';
$sql .= $this->quoteTableName($table->getName()) . ' (';
$sqlBuffer = [];
$columnsWithComments = [];
foreach ($columns as $column) {
$sqlBuffer[] = $this->quoteColumnName($column->getName()) . ' ' . $this->getColumnSqlDefinition($column);
// set column comments, if needed
if ($column->getComment()) {
$columnsWithComments[] = $column;
}
}
// set the primary key(s)
if (isset($options['primary_key'])) {
$pkSql = sprintf('CONSTRAINT PK_%s PRIMARY KEY (', $table->getName());
if (is_string($options['primary_key'])) { // handle primary_key => 'id'
$pkSql .= $this->quoteColumnName($options['primary_key']);
} elseif (is_array($options['primary_key'])) { // handle primary_key => array('tag_id', 'resource_id')
$pkSql .= implode(',', array_map([$this, 'quoteColumnName'], $options['primary_key']));
}
$pkSql .= ')';
$sqlBuffer[] = $pkSql;
}
// set the foreign keys
$foreignKeys = $table->getForeignKeys();
foreach ($foreignKeys as $foreignKey) {
$sqlBuffer[] = $this->getForeignKeySqlDefinition($foreignKey, $table->getName());
}
$sql .= implode(', ', $sqlBuffer);
$sql .= ');';
// process column comments
foreach ($columnsWithComments as $column) {
$sql .= $this->getColumnCommentSqlDefinition($column, $table->getName());
}
// set the indexes
$indexes = $table->getIndexes();
foreach ($indexes as $index) {
$sql .= $this->getIndexSqlDefinition($index, $table->getName());
}
// execute the sql
$this->execute($sql);
}
/**
* Gets the SqlServer Column Comment Defininition for a column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @param string $tableName Table name
*
* @return string
*/
protected function getColumnCommentSqlDefinition(Column $column, $tableName)
{
// passing 'null' is to remove column comment
$currentComment = $this->getColumnComment($tableName, $column->getName());
$comment = (strcasecmp($column->getComment(), 'NULL') !== 0) ? $this->getConnection()->quote($column->getComment()) : '\'\'';
$command = $currentComment === false ? 'sp_addextendedproperty' : 'sp_updateextendedproperty';
return sprintf(
"EXECUTE %s N'MS_Description', N%s, N'SCHEMA', N'%s', N'TABLE', N'%s', N'COLUMN', N'%s';",
$command,
$comment,
$this->schema,
$tableName,
$column->getName()
);
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$this->execute(sprintf('EXEC sp_rename \'%s\', \'%s\'', $tableName, $newTableName));
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$this->execute(sprintf('DROP TABLE %s', $this->quoteTableName($tableName)));
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$sql = sprintf(
'TRUNCATE TABLE %s',
$this->quoteTableName($tableName)
);
$this->execute($sql);
}
public function getColumnComment($tableName, $columnName)
{
$sql = sprintf("SELECT cast(extended_properties.[value] as nvarchar(4000)) comment
FROM sys.schemas
INNER JOIN sys.tables
ON schemas.schema_id = tables.schema_id
INNER JOIN sys.columns
ON tables.object_id = columns.object_id
INNER JOIN sys.extended_properties
ON tables.object_id = extended_properties.major_id
AND columns.column_id = extended_properties.minor_id
AND extended_properties.name = 'MS_Description'
WHERE schemas.[name] = '%s' AND tables.[name] = '%s' AND columns.[name] = '%s'", $this->schema, $tableName, $columnName);
$row = $this->fetchRow($sql);
if ($row) {
return $row['comment'];
}
return false;
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
$columns = [];
$sql = sprintf(
"SELECT DISTINCT TABLE_SCHEMA AS [schema], TABLE_NAME as [table_name], COLUMN_NAME AS [name], DATA_TYPE AS [type],
IS_NULLABLE AS [null], COLUMN_DEFAULT AS [default],
CHARACTER_MAXIMUM_LENGTH AS [char_length],
NUMERIC_PRECISION AS [precision],
NUMERIC_SCALE AS [scale], ORDINAL_POSITION AS [ordinal_position],
COLUMNPROPERTY(object_id(TABLE_NAME), COLUMN_NAME, 'IsIdentity') as [identity]
FROM INFORMATION_SCHEMA.COLUMNS
WHERE TABLE_NAME = '%s'
ORDER BY ordinal_position",
$tableName
);
$rows = $this->fetchAll($sql);
foreach ($rows as $columnInfo) {
$column = new Column();
$column->setName($columnInfo['name'])
->setType($this->getPhinxType($columnInfo['type']))
->setNull($columnInfo['null'] !== 'NO')
->setDefault($this->parseDefault($columnInfo['default']))
->setIdentity($columnInfo['identity'] === '1')
->setComment($this->getColumnComment($columnInfo['table_name'], $columnInfo['name']));
if (!empty($columnInfo['char_length'])) {
$column->setLimit($columnInfo['char_length']);
}
$columns[$columnInfo['name']] = $column;
}
return $columns;
}
protected function parseDefault($default)
{
$default = preg_replace(["/\('(.*)'\)/", "/\(\((.*)\)\)/", "/\((.*)\)/"], '$1', $default);
if (strtoupper($default) === 'NULL') {
$default = null;
} elseif (is_numeric($default)) {
$default = (int)$default;
}
return $default;
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
$sql = sprintf(
"SELECT count(*) as [count]
FROM information_schema.columns
WHERE table_name = '%s' AND column_name = '%s'",
$tableName,
$columnName
);
$result = $this->fetchRow($sql);
return $result['count'] > 0;
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$sql = sprintf(
'ALTER TABLE %s ADD %s %s',
$this->quoteTableName($table->getName()),
$this->quoteColumnName($column->getName()),
$this->getColumnSqlDefinition($column)
);
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
if (!$this->hasColumn($tableName, $columnName)) {
throw new \InvalidArgumentException("The specified column does not exist: $columnName");
}
$this->renameDefault($tableName, $columnName, $newColumnName);
$this->execute(
sprintf(
"EXECUTE sp_rename N'%s.%s', N'%s', 'COLUMN' ",
$tableName,
$columnName,
$newColumnName
)
);
}
protected function renameDefault($tableName, $columnName, $newColumnName)
{
$oldConstraintName = "DF_{$tableName}_{$columnName}";
$newConstraintName = "DF_{$tableName}_{$newColumnName}";
$sql = <<execute(sprintf(
$sql,
$oldConstraintName,
$newConstraintName
));
}
public function changeDefault($tableName, Column $newColumn)
{
$constraintName = "DF_{$tableName}_{$newColumn->getName()}";
$default = $newColumn->getDefault();
if ($default === null) {
$default = 'DEFAULT NULL';
} else {
$default = $this->getDefaultValueDefinition($default);
}
if (empty($default)) {
return;
}
$this->execute(sprintf(
'ALTER TABLE %s ADD CONSTRAINT %s %s FOR %s',
$this->quoteTableName($tableName),
$constraintName,
$default,
$this->quoteColumnName($newColumn->getName())
));
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
$columns = $this->getColumns($tableName);
$changeDefault = $newColumn->getDefault() !== $columns[$columnName]->getDefault() || $newColumn->getType() !== $columns[$columnName]->getType();
if ($columnName !== $newColumn->getName()) {
$this->renameColumn($tableName, $columnName, $newColumn->getName());
}
if ($changeDefault) {
$this->dropDefaultConstraint($tableName, $newColumn->getName());
}
$this->execute(
sprintf(
'ALTER TABLE %s ALTER COLUMN %s %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($newColumn->getName()),
$this->getColumnSqlDefinition($newColumn, false)
)
);
// change column comment if needed
if ($newColumn->getComment()) {
$sql = $this->getColumnCommentSqlDefinition($newColumn, $tableName);
$this->execute($sql);
}
if ($changeDefault) {
$this->changeDefault($tableName, $newColumn);
}
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$this->dropDefaultConstraint($tableName, $columnName);
$this->execute(
sprintf(
'ALTER TABLE %s DROP COLUMN %s',
$this->quoteTableName($tableName),
$this->quoteColumnName($columnName)
)
);
}
protected function dropDefaultConstraint($tableName, $columnName)
{
$defaultConstraint = $this->getDefaultConstraint($tableName, $columnName);
if (!$defaultConstraint) {
return;
}
$this->dropForeignKey($tableName, $columnName, $defaultConstraint);
}
protected function getDefaultConstraint($tableName, $columnName)
{
$sql = "SELECT
default_constraints.name
FROM
sys.all_columns
INNER JOIN
sys.tables
ON all_columns.object_id = tables.object_id
INNER JOIN
sys.schemas
ON tables.schema_id = schemas.schema_id
INNER JOIN
sys.default_constraints
ON all_columns.default_object_id = default_constraints.object_id
WHERE
schemas.name = 'dbo'
AND tables.name = '{$tableName}'
AND all_columns.name = '{$columnName}'";
$rows = $this->fetchAll($sql);
return empty($rows) ? false : $rows[0]['name'];
}
protected function getIndexColums($tableId, $indexId)
{
$sql = "SELECT AC.[name] AS [column_name]
FROM sys.[index_columns] IC
INNER JOIN sys.[all_columns] AC ON IC.[column_id] = AC.[column_id]
WHERE AC.[object_id] = {$tableId} AND IC.[index_id] = {$indexId} AND IC.[object_id] = {$tableId}
ORDER BY IC.[key_ordinal];";
$rows = $this->fetchAll($sql);
$columns = [];
foreach ($rows as $row) {
$columns[] = strtolower($row['column_name']);
}
return $columns;
}
/**
* Get an array of indexes from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
public function getIndexes($tableName)
{
$indexes = [];
$sql = "SELECT I.[name] AS [index_name], I.[index_id] as [index_id], T.[object_id] as [table_id]
FROM sys.[tables] AS T
INNER JOIN sys.[indexes] I ON T.[object_id] = I.[object_id]
WHERE T.[is_ms_shipped] = 0 AND I.[type_desc] <> 'HEAP' AND T.[name] = '{$tableName}'
ORDER BY T.[name], I.[index_id];";
$rows = $this->fetchAll($sql);
foreach ($rows as $row) {
$columns = $this->getIndexColums($row['table_id'], $row['index_id']);
$indexes[$row['index_name']] = ['columns' => $columns];
}
return $indexes;
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$columns = array_map('strtolower', $columns);
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $index) {
$a = array_diff($columns, $index['columns']);
if (empty($a)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $name => $index) {
if ($name === $indexName) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$sql = $this->getIndexSqlDefinition($index, $table->getName());
$this->execute($sql);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$indexes = $this->getIndexes($tableName);
$columns = array_map('strtolower', $columns);
foreach ($indexes as $indexName => $index) {
$a = array_diff($columns, $index['columns']);
if (empty($a)) {
$this->execute(
sprintf(
'DROP INDEX %s ON %s',
$this->quoteColumnName($indexName),
$this->quoteTableName($tableName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$indexes = $this->getIndexes($tableName);
foreach ($indexes as $name => $index) {
if ($name === $indexName) {
$this->execute(
sprintf(
'DROP INDEX %s ON %s',
$this->quoteColumnName($indexName),
$this->quoteTableName($tableName)
)
);
return;
}
}
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$foreignKeys = $this->getForeignKeys($tableName);
if ($constraint) {
if (isset($foreignKeys[$constraint])) {
return !empty($foreignKeys[$constraint]);
}
return false;
} else {
foreach ($foreignKeys as $key) {
$a = array_diff($columns, $key['columns']);
if (empty($a)) {
return true;
}
}
return false;
}
}
/**
* Get an array of foreign keys from a particular table.
*
* @param string $tableName Table Name
* @return array
*/
protected function getForeignKeys($tableName)
{
$foreignKeys = [];
$rows = $this->fetchAll(sprintf(
"SELECT
tc.constraint_name,
tc.table_name, kcu.column_name,
ccu.table_name AS referenced_table_name,
ccu.column_name AS referenced_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = '%s'
ORDER BY kcu.ordinal_position",
$tableName
));
foreach ($rows as $row) {
$foreignKeys[$row['constraint_name']]['table'] = $row['table_name'];
$foreignKeys[$row['constraint_name']]['columns'][] = $row['column_name'];
$foreignKeys[$row['constraint_name']]['referenced_table'] = $row['referenced_table_name'];
$foreignKeys[$row['constraint_name']]['referenced_columns'][] = $row['referenced_column_name'];
}
return $foreignKeys;
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$this->execute(
sprintf(
'ALTER TABLE %s ADD %s',
$this->quoteTableName($table->getName()),
$this->getForeignKeySqlDefinition($foreignKey, $table->getName())
)
);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
if ($constraint) {
$this->execute(
sprintf(
'ALTER TABLE %s DROP CONSTRAINT %s',
$this->quoteTableName($tableName),
$constraint
)
);
return;
} else {
foreach ($columns as $column) {
$rows = $this->fetchAll(sprintf(
"SELECT
tc.constraint_name,
tc.table_name, kcu.column_name,
ccu.table_name AS referenced_table_name,
ccu.column_name AS referenced_column_name
FROM
information_schema.table_constraints AS tc
JOIN information_schema.key_column_usage AS kcu ON tc.constraint_name = kcu.constraint_name
JOIN information_schema.constraint_column_usage AS ccu ON ccu.constraint_name = tc.constraint_name
WHERE constraint_type = 'FOREIGN KEY' AND tc.table_name = '%s' and ccu.column_name='%s'
ORDER BY kcu.ordinal_position",
$tableName,
$column
));
foreach ($rows as $row) {
$this->dropForeignKey($tableName, $columns, $row['constraint_name']);
}
}
}
}
/**
* {@inheritdoc}
*/
public function getSqlType($type, $limit = null)
{
switch ($type) {
case static::PHINX_TYPE_STRING:
return ['name' => 'nvarchar', 'limit' => 255];
case static::PHINX_TYPE_CHAR:
return ['name' => 'nchar', 'limit' => 255];
case static::PHINX_TYPE_TEXT:
return ['name' => 'ntext'];
case static::PHINX_TYPE_INTEGER:
return ['name' => 'int'];
case static::PHINX_TYPE_BIG_INTEGER:
return ['name' => 'bigint'];
case static::PHINX_TYPE_FLOAT:
return ['name' => 'float'];
case static::PHINX_TYPE_DECIMAL:
return ['name' => 'decimal'];
case static::PHINX_TYPE_DATETIME:
case static::PHINX_TYPE_TIMESTAMP:
return ['name' => 'datetime'];
case static::PHINX_TYPE_TIME:
return ['name' => 'time'];
case static::PHINX_TYPE_DATE:
return ['name' => 'date'];
case static::PHINX_TYPE_BLOB:
case static::PHINX_TYPE_BINARY:
return ['name' => 'varbinary'];
case static::PHINX_TYPE_BOOLEAN:
return ['name' => 'bit'];
case static::PHINX_TYPE_UUID:
return ['name' => 'uniqueidentifier'];
case static::PHINX_TYPE_FILESTREAM:
return ['name' => 'varbinary', 'limit' => 'max'];
// Geospatial database types
case static::PHINX_TYPE_GEOMETRY:
case static::PHINX_TYPE_POINT:
case static::PHINX_TYPE_LINESTRING:
case static::PHINX_TYPE_POLYGON:
// SQL Server stores all spatial data using a single data type.
// Specific types (point, polygon, etc) are set at insert time.
return ['name' => 'geography'];
default:
throw new \RuntimeException('The type: "' . $type . '" is not supported.');
}
}
/**
* Returns Phinx type by SQL type
*
* @param string $sqlType SQL Type definition
* @throws \RuntimeException
* @internal param string $sqlType SQL type
* @returns string Phinx type
*/
public function getPhinxType($sqlType)
{
switch ($sqlType) {
case 'nvarchar':
case 'varchar':
return static::PHINX_TYPE_STRING;
case 'char':
case 'nchar':
return static::PHINX_TYPE_CHAR;
case 'text':
case 'ntext':
return static::PHINX_TYPE_TEXT;
case 'int':
case 'integer':
return static::PHINX_TYPE_INTEGER;
case 'decimal':
case 'numeric':
case 'money':
return static::PHINX_TYPE_DECIMAL;
case 'bigint':
return static::PHINX_TYPE_BIG_INTEGER;
case 'real':
case 'float':
return static::PHINX_TYPE_FLOAT;
case 'binary':
case 'image':
case 'varbinary':
return static::PHINX_TYPE_BINARY;
case 'time':
return static::PHINX_TYPE_TIME;
case 'date':
return static::PHINX_TYPE_DATE;
case 'datetime':
case 'timestamp':
return static::PHINX_TYPE_DATETIME;
case 'bit':
return static::PHINX_TYPE_BOOLEAN;
case 'uniqueidentifier':
return static::PHINX_TYPE_UUID;
case 'filestream':
return static::PHINX_TYPE_FILESTREAM;
default:
throw new \RuntimeException('The SqlServer type: "' . $sqlType . '" is not supported');
}
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
if (isset($options['collation'])) {
$this->execute(sprintf('CREATE DATABASE [%s] COLLATE [%s]', $name, $options['collation']));
} else {
$this->execute(sprintf('CREATE DATABASE [%s]', $name));
}
$this->execute(sprintf('USE [%s]', $name));
}
/**
* {@inheritdoc}
*/
public function hasDatabase($name)
{
$result = $this->fetchRow(
sprintf(
'SELECT count(*) as [count] FROM master.dbo.sysdatabases WHERE [name] = \'%s\'',
$name
)
);
return $result['count'] > 0;
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$sql = <<execute($sql);
}
/**
* Get the defintion for a `DEFAULT` statement.
*
* @param mixed $default
* @return string
*/
protected function getDefaultValueDefinition($default)
{
if (is_string($default) && 'CURRENT_TIMESTAMP' !== $default) {
$default = $this->getConnection()->quote($default);
} elseif (is_bool($default)) {
$default = $this->castToBool($default);
}
return isset($default) ? ' DEFAULT ' . $default : '';
}
/**
* Gets the SqlServer Column Definition for a Column object.
*
* @param \Phinx\Db\Table\Column $column Column
* @return string
*/
protected function getColumnSqlDefinition(Column $column, $create = true)
{
$buffer = [];
$sqlType = $this->getSqlType($column->getType());
$buffer[] = strtoupper($sqlType['name']);
// integers cant have limits in SQlServer
$noLimits = [
'bigint',
'int',
'tinyint'
];
if (!in_array($sqlType['name'], $noLimits) && ($column->getLimit() || isset($sqlType['limit']))) {
$buffer[] = sprintf('(%s)', $column->getLimit() ?: $sqlType['limit']);
}
if ($column->getPrecision() && $column->getScale()) {
$buffer[] = '(' . $column->getPrecision() . ',' . $column->getScale() . ')';
}
$properties = $column->getProperties();
$buffer[] = $column->getType() === 'filestream' ? 'FILESTREAM' : '';
$buffer[] = isset($properties['rowguidcol']) ? 'ROWGUIDCOL' : '';
$buffer[] = $column->isNull() ? 'NULL' : 'NOT NULL';
if ($create === true) {
if ($column->getDefault() === null && $column->isNull()) {
$buffer[] = ' DEFAULT NULL';
} else {
$buffer[] = $this->getDefaultValueDefinition($column->getDefault());
}
}
if ($column->isIdentity()) {
$buffer[] = 'IDENTITY(1, 1)';
}
return implode(' ', $buffer);
}
/**
* Gets the SqlServer Index Definition for an Index object.
*
* @param \Phinx\Db\Table\Index $index Index
* @return string
*/
protected function getIndexSqlDefinition(Index $index, $tableName)
{
if (is_string($index->getName())) {
$indexName = $index->getName();
} else {
$columnNames = $index->getColumns();
if (is_string($columnNames)) {
$columnNames = [$columnNames];
}
$indexName = sprintf('%s_%s', $tableName, implode('_', $columnNames));
}
$def = sprintf(
"CREATE %s INDEX %s ON %s (%s);",
($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''),
$indexName,
$this->quoteTableName($tableName),
'[' . implode('],[', $index->getColumns()) . ']'
);
return $def;
}
/**
* Gets the SqlServer Foreign Key Definition for an ForeignKey object.
*
* @param \Phinx\Db\Table\ForeignKey $foreignKey
* @return string
*/
protected function getForeignKeySqlDefinition(ForeignKey $foreignKey, $tableName)
{
$constraintName = $foreignKey->getConstraint() ?: $tableName . '_' . implode('_', $foreignKey->getColumns());
$def = ' CONSTRAINT ' . $this->quoteColumnName($constraintName);
$def .= ' FOREIGN KEY ("' . implode('", "', $foreignKey->getColumns()) . '")';
$def .= " REFERENCES {$this->quoteTableName($foreignKey->getReferencedTable()->getName())} (\"" . implode('", "', $foreignKey->getReferencedColumns()) . '")';
if ($foreignKey->getOnDelete()) {
$def .= " ON DELETE {$foreignKey->getOnDelete()}";
}
if ($foreignKey->getOnUpdate()) {
$def .= " ON UPDATE {$foreignKey->getOnUpdate()}";
}
return $def;
}
/**
* {@inheritdoc}
*/
public function getColumnTypes()
{
return array_merge(parent::getColumnTypes(), ['filestream']);
}
/**
* Records a migration being run.
*
* @param \Phinx\Migration\MigrationInterface $migration Migration
* @param string $direction Direction
* @param int $startTime Start Time
* @param int $endTime End Time
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function migrated(\Phinx\Migration\MigrationInterface $migration, $direction, $startTime, $endTime)
{
$startTime = str_replace(' ', 'T', $startTime);
$endTime = str_replace(' ', 'T', $endTime);
return parent::migrated($migration, $direction, $startTime, $endTime);
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/TablePrefixAdapter.php 0000664 0000000 0000000 00000020010 13217376123 0022647 0 ustar 00root root 0000000 0000000
*/
class TablePrefixAdapter extends AdapterWrapper
{
/**
* {@inheritdoc}
*/
public function getAdapterType()
{
return 'TablePrefixAdapter';
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::hasTable($adapterTableName);
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
foreach ($adapterTable->getForeignKeys() as $fk) {
$adapterReferenceTable = $fk->getReferencedTable();
$adapterReferenceTableName = $this->getAdapterTableName($adapterReferenceTable->getName());
$adapterReferenceTable->setName($adapterReferenceTableName);
}
parent::createTable($adapterTable);
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
$adapterNewTableName = $this->getAdapterTableName($newTableName);
parent::renameTable($adapterTableName, $adapterNewTableName);
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::dropTable($adapterTableName);
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::truncateTable($adapterTableName);
}
/**
* {@inheritdoc}
*/
public function getColumns($tableName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::getColumns($adapterTableName);
}
/**
* {@inheritdoc}
*/
public function hasColumn($tableName, $columnName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::hasColumn($adapterTableName, $columnName);
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
parent::addColumn($adapterTable, $column);
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::renameColumn($adapterTableName, $columnName, $newColumnName);
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::changeColumn($adapterTableName, $columnName, $newColumn);
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::dropColumn($adapterTableName, $columnName);
}
/**
* {@inheritdoc}
*/
public function hasIndex($tableName, $columns)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::hasIndex($adapterTableName, $columns);
}
/**
* {@inheritdoc}
*/
public function hasIndexByName($tableName, $indexName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::hasIndexByName($adapterTableName, $indexName);
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
parent::addIndex($adapterTable, $index);
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::dropIndex($adapterTableName, $columns);
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::dropIndexByName($adapterTableName, $indexName);
}
/**
* {@inheritdoc}
*/
public function hasForeignKey($tableName, $columns, $constraint = null)
{
$adapterTableName = $this->getAdapterTableName($tableName);
return parent::hasForeignKey($adapterTableName, $columns, $constraint);
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
parent::addForeignKey($adapterTable, $foreignKey);
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
$adapterTableName = $this->getAdapterTableName($tableName);
parent::dropForeignKey($adapterTableName, $columns, $constraint);
}
/**
* {@inheritdoc}
*/
public function insert(Table $table, $row)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
parent::insert($adapterTable, $row);
}
/**
* {@inheritdoc}
*/
public function bulkinsert(Table $table, $rows)
{
$adapterTable = clone $table;
$adapterTableName = $this->getAdapterTableName($table->getName());
$adapterTable->setName($adapterTableName);
parent::bulkinsert($adapterTable, $rows);
}
/**
* Gets the table prefix.
*
* @return string
*/
public function getPrefix()
{
return (string)$this->getOption('table_prefix');
}
/**
* Gets the table suffix.
*
* @return string
*/
public function getSuffix()
{
return (string)$this->getOption('table_suffix');
}
/**
* Applies the prefix and suffix to the table name.
*
* @param string $tableName
* @return string
*/
public function getAdapterTableName($tableName)
{
return $this->getPrefix() . $tableName . $this->getSuffix();
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/TimedOutputAdapter.php 0000664 0000000 0000000 00000021146 13217376123 0022740 0 ustar 00root root 0000000 0000000 getAdapter()->getAdapterType();
}
/**
* Start timing a command.
*
* @return callable A function that is to be called when the command finishes
*/
public function startCommandTimer()
{
$started = microtime(true);
return function () use ($started) {
$end = microtime(true);
if (OutputInterface::VERBOSITY_VERBOSE <= $this->getOutput()->getVerbosity()) {
$this->getOutput()->writeln(' -> ' . sprintf('%.4fs', $end - $started));
}
};
}
/**
* Write a Phinx command to the output.
*
* @param string $command Command Name
* @param array $args Command Args
* @return void
*/
public function writeCommand($command, $args = [])
{
if (OutputInterface::VERBOSITY_VERBOSE > $this->getOutput()->getVerbosity()) {
return;
}
if (count($args)) {
$outArr = [];
foreach ($args as $arg) {
if (is_array($arg)) {
$arg = array_map(
function ($value) {
return '\'' . $value . '\'';
},
$arg
);
$outArr[] = '[' . implode(', ', $arg) . ']';
continue;
}
$outArr[] = '\'' . $arg . '\'';
}
$this->getOutput()->writeln(' -- ' . $command . '(' . implode(', ', $outArr) . ')');
return;
}
$this->getOutput()->writeln(' -- ' . $command);
}
/**
* {@inheritdoc}
*
* @return void
*/
public function insert(Table $table, $row)
{
$end = $this->startCommandTimer();
$this->writeCommand('insert', [$table->getName()]);
parent::insert($table, $row);
$end();
}
/**
* {@inheritdoc}
*
* @return void
*/
public function bulkinsert(Table $table, $rows)
{
$end = $this->startCommandTimer();
$this->writeCommand('bulkinsert', [$table->getName()]);
parent::bulkinsert($table, $rows);
$end();
}
/**
* {@inheritdoc}
*/
public function createTable(Table $table)
{
$end = $this->startCommandTimer();
$this->writeCommand('createTable', [$table->getName()]);
parent::createTable($table);
$end();
}
/**
* {@inheritdoc}
*/
public function renameTable($tableName, $newTableName)
{
$end = $this->startCommandTimer();
$this->writeCommand('renameTable', [$tableName, $newTableName]);
parent::renameTable($tableName, $newTableName);
$end();
}
/**
* {@inheritdoc}
*/
public function dropTable($tableName)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropTable', [$tableName]);
parent::dropTable($tableName);
$end();
}
/**
* {@inheritdoc}
*/
public function truncateTable($tableName)
{
$end = $this->startCommandTimer();
$this->writeCommand('truncateTable', [$tableName]);
parent::truncateTable($tableName);
$end();
}
/**
* {@inheritdoc}
*/
public function addColumn(Table $table, Column $column)
{
$end = $this->startCommandTimer();
$this->writeCommand(
'addColumn',
[
$table->getName(),
$column->getName(),
$column->getType()
]
);
parent::addColumn($table, $column);
$end();
}
/**
* {@inheritdoc}
*/
public function renameColumn($tableName, $columnName, $newColumnName)
{
$end = $this->startCommandTimer();
$this->writeCommand('renameColumn', [$tableName, $columnName, $newColumnName]);
parent::renameColumn($tableName, $columnName, $newColumnName);
$end();
}
/**
* {@inheritdoc}
*/
public function changeColumn($tableName, $columnName, Column $newColumn)
{
$end = $this->startCommandTimer();
$this->writeCommand('changeColumn', [$tableName, $columnName, $newColumn->getType()]);
parent::changeColumn($tableName, $columnName, $newColumn);
$end();
}
/**
* {@inheritdoc}
*/
public function dropColumn($tableName, $columnName)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropColumn', [$tableName, $columnName]);
parent::dropColumn($tableName, $columnName);
$end();
}
/**
* {@inheritdoc}
*/
public function addIndex(Table $table, Index $index)
{
$end = $this->startCommandTimer();
$this->writeCommand('addIndex', [$table->getName(), $index->getColumns()]);
parent::addIndex($table, $index);
$end();
}
/**
* {@inheritdoc}
*/
public function dropIndex($tableName, $columns)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropIndex', [$tableName, $columns]);
parent::dropIndex($tableName, $columns);
$end();
}
/**
* {@inheritdoc}
*/
public function dropIndexByName($tableName, $indexName)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropIndexByName', [$tableName, $indexName]);
parent::dropIndexByName($tableName, $indexName);
$end();
}
/**
* {@inheritdoc}
*/
public function addForeignKey(Table $table, ForeignKey $foreignKey)
{
$end = $this->startCommandTimer();
$this->writeCommand('addForeignKey', [$table->getName(), $foreignKey->getColumns()]);
parent::addForeignKey($table, $foreignKey);
$end();
}
/**
* {@inheritdoc}
*/
public function dropForeignKey($tableName, $columns, $constraint = null)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropForeignKey', [$tableName, $columns]);
parent::dropForeignKey($tableName, $columns, $constraint);
$end();
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options = [])
{
$end = $this->startCommandTimer();
$this->writeCommand('createDatabase', [$name]);
parent::createDatabase($name, $options);
$end();
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropDatabase', [$name]);
parent::dropDatabase($name);
$end();
}
/**
* {@inheritdoc}
*/
public function createSchema($name = 'public')
{
$end = $this->startCommandTimer();
$this->writeCommand('createSchema', [$name]);
parent::createSchema($name);
$end();
}
/**
* {@inheritdoc}
*/
public function dropSchema($name)
{
$end = $this->startCommandTimer();
$this->writeCommand('dropSchema', [$name]);
parent::dropSchema($name);
$end();
}
}
phinx-0.9.2/src/Phinx/Db/Adapter/WrapperInterface.php 0000664 0000000 0000000 00000003727 13217376123 0022422 0 ustar 00root root 0000000 0000000
*/
interface WrapperInterface
{
/**
* Class constructor, must always wrap another adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter
*/
public function __construct(AdapterInterface $adapter);
/**
* Sets the database adapter to proxy commands to.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function setAdapter(AdapterInterface $adapter);
/**
* Gets the database adapter.
*
* @throws \RuntimeException if the adapter has not been set
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter();
}
phinx-0.9.2/src/Phinx/Db/Table.php 0000664 0000000 0000000 00000043445 13217376123 0016631 0 ustar 00root root 0000000 0000000 setName($name);
$this->setOptions($options);
if ($adapter !== null) {
$this->setAdapter($adapter);
}
}
/**
* Sets the table name.
*
* @param string $name Table Name
* @return \Phinx\Db\Table
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Gets the table name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Sets the table options.
*
* @param array $options
* @return \Phinx\Db\Table
*/
public function setOptions($options)
{
$this->options = $options;
return $this;
}
/**
* Gets the table options.
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* Sets the database adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
* @return \Phinx\Db\Table
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* Gets the database adapter.
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* Does the table exist?
*
* @return bool
*/
public function exists()
{
return $this->getAdapter()->hasTable($this->getName());
}
/**
* Drops the database table.
*
* @return void
*/
public function drop()
{
$this->getAdapter()->dropTable($this->getName());
}
/**
* Renames the database table.
*
* @param string $newTableName New Table Name
* @return \Phinx\Db\Table
*/
public function rename($newTableName)
{
$this->getAdapter()->renameTable($this->getName(), $newTableName);
$this->setName($newTableName);
return $this;
}
/**
* Sets an array of columns waiting to be committed.
* Use setPendingColumns
*
* @deprecated
* @param array $columns Columns
* @return \Phinx\Db\Table
*/
public function setColumns($columns)
{
$this->setPendingColumns($columns);
return $this;
}
/**
* Gets an array of the table columns.
*
* @return \Phinx\Db\Table\Column[]
*/
public function getColumns()
{
return $this->getAdapter()->getColumns($this->getName());
}
/**
* Sets an array of columns waiting to be committed.
*
* @param array $columns Columns
* @return \Phinx\Db\Table
*/
public function setPendingColumns($columns)
{
$this->columns = $columns;
return $this;
}
/**
* Gets an array of columns waiting to be committed.
*
* @return \Phinx\Db\Table\Column[]
*/
public function getPendingColumns()
{
return $this->columns;
}
/**
* Sets an array of columns waiting to be indexed.
*
* @param array $indexes Indexes
* @return \Phinx\Db\Table
*/
public function setIndexes($indexes)
{
$this->indexes = $indexes;
return $this;
}
/**
* Gets an array of indexes waiting to be committed.
*
* @return array
*/
public function getIndexes()
{
return $this->indexes;
}
/**
* Sets an array of foreign keys waiting to be commited.
*
* @param \Phinx\Db\Table\ForeignKey[] $foreignKeys foreign keys
* @return \Phinx\Db\Table
*/
public function setForeignKeys($foreignKeys)
{
$this->foreignKeys = $foreignKeys;
return $this;
}
/**
* Gets an array of foreign keys waiting to be commited.
*
* @return array|\Phinx\Db\Table\ForeignKey[]
*/
public function getForeignKeys()
{
return $this->foreignKeys;
}
/**
* Sets an array of data to be inserted.
*
* @param array $data Data
* @return \Phinx\Db\Table
*/
public function setData($data)
{
$this->data = $data;
return $this;
}
/**
* Gets the data waiting to be inserted.
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* Resets all of the pending table changes.
*
* @return void
*/
public function reset()
{
$this->setPendingColumns([]);
$this->setIndexes([]);
$this->setForeignKeys([]);
$this->setData([]);
}
/**
* Add a table column.
*
* Type can be: string, text, integer, float, decimal, datetime, timestamp,
* time, date, binary, boolean.
*
* Valid options can be: limit, default, null, precision or scale.
*
* @param string|\Phinx\Db\Table\Column $columnName Column Name
* @param string $type Column Type
* @param array $options Column Options
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return \Phinx\Db\Table
*/
public function addColumn($columnName, $type = null, $options = [])
{
// we need an adapter set to add a column
if ($this->getAdapter() === null) {
throw new \RuntimeException('An adapter must be specified to add a column.');
}
// create a new column object if only strings were supplied
if (!$columnName instanceof Column) {
$column = new Column();
$column->setName($columnName);
$column->setType($type);
$column->setOptions($options); // map options to column methods
} else {
$column = $columnName;
}
// Delegate to Adapters to check column type
if (!$this->getAdapter()->isValidColumnType($column)) {
throw new \InvalidArgumentException(sprintf(
'An invalid column type "%s" was specified for column "%s".',
$column->getType(),
$column->getName()
));
}
$this->columns[] = $column;
return $this;
}
/**
* Remove a table column.
*
* @param string $columnName Column Name
* @return \Phinx\Db\Table
*/
public function removeColumn($columnName)
{
$this->getAdapter()->dropColumn($this->getName(), $columnName);
return $this;
}
/**
* Rename a table column.
*
* @param string $oldName Old Column Name
* @param string $newName New Column Name
* @return \Phinx\Db\Table
*/
public function renameColumn($oldName, $newName)
{
$this->getAdapter()->renameColumn($this->getName(), $oldName, $newName);
return $this;
}
/**
* Change a table column type.
*
* @param string $columnName Column Name
* @param string|\Phinx\Db\Table\Column $newColumnType New Column Type
* @param array $options Options
* @return \Phinx\Db\Table
*/
public function changeColumn($columnName, $newColumnType, $options = [])
{
// create a column object if one wasn't supplied
if (!$newColumnType instanceof Column) {
$newColumn = new Column();
$newColumn->setType($newColumnType);
$newColumn->setOptions($options);
} else {
$newColumn = $newColumnType;
}
// if the name was omitted use the existing column name
if ($newColumn->getName() === null || strlen($newColumn->getName()) === 0) {
$newColumn->setName($columnName);
}
$this->getAdapter()->changeColumn($this->getName(), $columnName, $newColumn);
return $this;
}
/**
* Checks to see if a column exists.
*
* @param string $columnName Column Name
* @return bool
*/
public function hasColumn($columnName)
{
return $this->getAdapter()->hasColumn($this->getName(), $columnName);
}
/**
* Add an index to a database table.
*
* In $options you can specific unique = true/false or name (index name).
*
* @param string|array|\Phinx\Db\Table\Index $columns Table Column(s)
* @param array $options Index Options
* @return \Phinx\Db\Table
*/
public function addIndex($columns, $options = [])
{
// create a new index object if strings or an array of strings were supplied
if (!$columns instanceof Index) {
$index = new Index();
if (is_string($columns)) {
$columns = [$columns]; // str to array
}
$index->setColumns($columns);
$index->setOptions($options);
} else {
$index = $columns;
}
$this->indexes[] = $index;
return $this;
}
/**
* Removes the given index from a table.
*
* @param array $columns Columns
* @return \Phinx\Db\Table
*/
public function removeIndex($columns)
{
$this->getAdapter()->dropIndex($this->getName(), $columns);
return $this;
}
/**
* Removes the given index identified by its name from a table.
*
* @param string $name Index name
* @return \Phinx\Db\Table
*/
public function removeIndexByName($name)
{
$this->getAdapter()->dropIndexByName($this->getName(), $name);
return $this;
}
/**
* Checks to see if an index exists.
*
* @param string|array $columns Columns
* @param array $options Options
* @return bool
*/
public function hasIndex($columns)
{
return $this->getAdapter()->hasIndex($this->getName(), $columns);
}
/**
* Add a foreign key to a database table.
*
* In $options you can specify on_delete|on_delete = cascade|no_action ..,
* on_update, constraint = constraint name.
*
* @param string|array $columns Columns
* @param string|\Phinx\Db\Table $referencedTable Referenced Table
* @param string|array $referencedColumns Referenced Columns
* @param array $options Options
* @return \Phinx\Db\Table
*/
public function addForeignKey($columns, $referencedTable, $referencedColumns = ['id'], $options = [])
{
if (is_string($referencedColumns)) {
$referencedColumns = [$referencedColumns]; // str to array
}
$fk = new ForeignKey();
if ($referencedTable instanceof Table) {
$fk->setReferencedTable($referencedTable);
} else {
$fk->setReferencedTable(new Table($referencedTable, [], $this->adapter));
}
$fk->setColumns($columns)
->setReferencedColumns($referencedColumns)
->setOptions($options);
$this->foreignKeys[] = $fk;
return $this;
}
/**
* Removes the given foreign key from the table.
*
* @param string|array $columns Column(s)
* @param null|string $constraint Constraint names
* @return \Phinx\Db\Table
*/
public function dropForeignKey($columns, $constraint = null)
{
if (is_string($columns)) {
$columns = [$columns];
}
if ($constraint) {
$this->getAdapter()->dropForeignKey($this->getName(), [], $constraint);
} else {
$this->getAdapter()->dropForeignKey($this->getName(), $columns);
}
return $this;
}
/**
* Checks to see if a foreign key exists.
*
* @param string|array $columns Column(s)
* @param null|string $constraint Constraint names
* @return bool
*/
public function hasForeignKey($columns, $constraint = null)
{
return $this->getAdapter()->hasForeignKey($this->getName(), $columns, $constraint);
}
/**
* Add timestamp columns created_at and updated_at to the table.
*
* @param string $createdAtColumnName
* @param string $updatedAtColumnName
*
* @return \Phinx\Db\Table
*/
public function addTimestamps($createdAtColumnName = 'created_at', $updatedAtColumnName = 'updated_at')
{
$createdAtColumnName = is_null($createdAtColumnName) ? 'created_at' : $createdAtColumnName;
$updatedAtColumnName = is_null($updatedAtColumnName) ? 'updated_at' : $updatedAtColumnName;
$this->addColumn($createdAtColumnName, 'timestamp', [
'default' => 'CURRENT_TIMESTAMP',
'update' => ''
])
->addColumn($updatedAtColumnName, 'timestamp', [
'null' => true,
'default' => null
]);
return $this;
}
/**
* Insert data into the table.
*
* @param array $data array of data in the form:
* array(
* array("col1" => "value1", "col2" => "anotherValue1"),
* array("col2" => "value2", "col2" => "anotherValue2"),
* )
* or array("col1" => "value1", "col2" => "anotherValue1")
*
* @return \Phinx\Db\Table
*/
public function insert($data)
{
// handle array of array situations
if (isset($data[0]) && is_array($data[0])) {
foreach ($data as $row) {
$this->data[] = $row;
}
return $this;
}
$this->data[] = $data;
return $this;
}
/**
* Creates a table from the object instance.
*
* @return void
*/
public function create()
{
$this->getAdapter()->createTable($this);
$this->saveData();
$this->reset(); // reset pending changes
}
/**
* Updates a table from the object instance.
*
* @throws \RuntimeException
* @return void
*/
public function update()
{
if (!$this->exists()) {
throw new \RuntimeException('Cannot update a table that doesn\'t exist!');
}
// update table
foreach ($this->getPendingColumns() as $column) {
$this->getAdapter()->addColumn($this, $column);
}
foreach ($this->getIndexes() as $index) {
$this->getAdapter()->addIndex($this, $index);
}
foreach ($this->getForeignKeys() as $foreignKey) {
$this->getAdapter()->addForeignKey($this, $foreignKey);
}
$this->saveData();
$this->reset(); // reset pending changes
}
/**
* Commit the pending data waiting for insertion.
*
* @return void
*/
public function saveData()
{
$rows = $this->getData();
if (empty($rows)) {
return;
}
$bulk = true;
$row = current($rows);
$c = array_keys($row);
foreach ($this->getData() as $row) {
$k = array_keys($row);
if ($k != $c) {
$bulk = false;
break;
}
}
if ($bulk) {
$this->getAdapter()->bulkinsert($this, $this->getData());
} else {
foreach ($this->getData() as $row) {
$this->getAdapter()->insert($this, $row);
}
}
}
/**
* Truncates the table.
*
* @return void
*/
public function truncate()
{
$this->getAdapter()->truncateTable($this->getName());
}
/**
* Commits the table changes.
*
* If the table doesn't exist it is created otherwise it is updated.
*
* @return void
*/
public function save()
{
if ($this->exists()) {
$this->update(); // update the table
} else {
$this->create(); // create the table
}
$this->reset(); // reset pending changes
}
}
phinx-0.9.2/src/Phinx/Db/Table/ 0000775 0000000 0000000 00000000000 13217376123 0016106 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Db/Table/Column.php 0000664 0000000 0000000 00000030600 13217376123 0020053 0 ustar 00root root 0000000 0000000 name = $name;
return $this;
}
/**
* Gets the column name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Sets the column type.
*
* @param string $type
* @return \Phinx\Db\Table\Column
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Gets the column type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Sets the column limit.
*
* @param int $limit
* @return \Phinx\Db\Table\Column
*/
public function setLimit($limit)
{
$this->limit = $limit;
return $this;
}
/**
* Gets the column limit.
*
* @return int
*/
public function getLimit()
{
return $this->limit;
}
/**
* Sets whether the column allows nulls.
*
* @param bool $null
* @return \Phinx\Db\Table\Column
*/
public function setNull($null)
{
$this->null = (bool)$null;
return $this;
}
/**
* Gets whether the column allows nulls.
*
* @return bool
*/
public function getNull()
{
return $this->null;
}
/**
* Does the column allow nulls?
*
* @return bool
*/
public function isNull()
{
return $this->getNull();
}
/**
* Sets the default column value.
*
* @param mixed $default
* @return \Phinx\Db\Table\Column
*/
public function setDefault($default)
{
$this->default = $default;
return $this;
}
/**
* Gets the default column value.
*
* @return mixed
*/
public function getDefault()
{
return $this->default;
}
/**
* Sets whether or not the column is an identity column.
*
* @param bool $identity
* @return \Phinx\Db\Table\Column
*/
public function setIdentity($identity)
{
$this->identity = $identity;
return $this;
}
/**
* Gets whether or not the column is an identity column.
*
* @return bool
*/
public function getIdentity()
{
return $this->identity;
}
/**
* Is the column an identity column?
*
* @return bool
*/
public function isIdentity()
{
return $this->getIdentity();
}
/**
* Sets the name of the column to add this column after.
*
* @param string $after After
* @return \Phinx\Db\Table\Column
*/
public function setAfter($after)
{
$this->after = $after;
return $this;
}
/**
* Returns the name of the column to add this column after.
*
* @return string
*/
public function getAfter()
{
return $this->after;
}
/**
* Sets the 'ON UPDATE' mysql column function.
*
* @param string $update On Update function
* @return \Phinx\Db\Table\Column
*/
public function setUpdate($update)
{
$this->update = $update;
return $this;
}
/**
* Returns the value of the ON UPDATE column function.
*
* @return string
*/
public function getUpdate()
{
return $this->update;
}
/**
* Sets the column precision for decimal.
*
* @param int $precision
* @return \Phinx\Db\Table\Column
*/
public function setPrecision($precision)
{
$this->precision = $precision;
return $this;
}
/**
* Gets the column precision for decimal.
*
* @return int
*/
public function getPrecision()
{
return $this->precision;
}
/**
* Sets the column scale for decimal.
*
* @param int $scale
* @return \Phinx\Db\Table\Column
*/
public function setScale($scale)
{
$this->scale = $scale;
return $this;
}
/**
* Gets the column scale for decimal.
*
* @return int
*/
public function getScale()
{
return $this->scale;
}
/**
* Sets the column comment.
*
* @param string $comment
* @return \Phinx\Db\Table\Column
*/
public function setComment($comment)
{
$this->comment = $comment;
return $this;
}
/**
* Gets the column comment.
*
* @return string
*/
public function getComment()
{
return $this->comment;
}
/**
* Sets whether field should be signed.
*
* @param bool $signed
* @return \Phinx\Db\Table\Column
*/
public function setSigned($signed)
{
$this->signed = (bool)$signed;
return $this;
}
/**
* Gets whether field should be signed.
*
* @return bool
*/
public function getSigned()
{
return $this->signed;
}
/**
* Should the column be signed?
*
* @return bool
*/
public function isSigned()
{
return $this->getSigned();
}
/**
* Sets whether the field should have a timezone identifier.
* Used for date/time columns only!
*
* @param bool $timezone
* @return \Phinx\Db\Table\Column
*/
public function setTimezone($timezone)
{
$this->timezone = (bool)$timezone;
return $this;
}
/**
* Gets whether field has a timezone identifier.
*
* @return bool
*/
public function getTimezone()
{
return $this->timezone;
}
/**
* Should the column have a timezone?
*
* @return bool
*/
public function isTimezone()
{
return $this->getTimezone();
}
/**
* Sets field properties.
*
* @param array $properties
*
* @return \Phinx\Db\Table\Column
*/
public function setProperties($properties)
{
$this->properties = $properties;
return $this;
}
/**
* Gets field properties
*
* @return array
*/
public function getProperties()
{
return $this->properties;
}
/**
* Sets field values.
*
* @param mixed (array|string) $values
*
* @return \Phinx\Db\Table\Column
*/
public function setValues($values)
{
if (!is_array($values)) {
$values = preg_split('/,\s*/', $values);
}
$this->values = $values;
return $this;
}
/**
* Gets field values
*
* @return array
*/
public function getValues()
{
return $this->values;
}
/**
* Sets the column collation.
*
* @param string $collation
*
* @throws \UnexpectedValueException If collation not allowed for type
* @return $this
*/
public function setCollation($collation)
{
$allowedTypes = [
AdapterInterface::PHINX_TYPE_CHAR,
AdapterInterface::PHINX_TYPE_STRING,
AdapterInterface::PHINX_TYPE_TEXT,
];
if (!in_array($this->getType(), $allowedTypes)) {
throw new \UnexpectedValueException('Collation may be set only for types: ' . implode(', ', $allowedTypes));
}
$this->collation = $collation;
return $this;
}
/**
* Gets the column collation.
*
* @return string
*/
public function getCollation()
{
return $this->collation;
}
/**
* Sets the column character set.
*
* @param string $encoding
*
* @throws \UnexpectedValueException If character set not allowed for type
* @return $this
*/
public function setEncoding($encoding)
{
$allowedTypes = [
AdapterInterface::PHINX_TYPE_CHAR,
AdapterInterface::PHINX_TYPE_STRING,
AdapterInterface::PHINX_TYPE_TEXT,
];
if (!in_array($this->getType(), $allowedTypes)) {
throw new \UnexpectedValueException('Character set may be set only for types: ' . implode(', ', $allowedTypes));
}
$this->encoding = $encoding;
return $this;
}
/**
* Gets the column character set.
*
* @return string
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* Gets all allowed options. Each option must have a corresponding `setFoo` method.
*
* @return array
*/
protected function getValidOptions()
{
return [
'limit',
'default',
'null',
'identity',
'precision',
'scale',
'after',
'update',
'comment',
'signed',
'timezone',
'properties',
'values',
'collation',
'encoding',
];
}
/**
* Gets all aliased options. Each alias must reference a valid option.
*
* @return array
*/
protected function getAliasedOptions()
{
return [
'length' => 'limit',
];
}
/**
* Utility method that maps an array of column options to this objects methods.
*
* @param array $options Options
* @return \Phinx\Db\Table\Column
*/
public function setOptions($options)
{
$validOptions = $this->getValidOptions();
$aliasOptions = $this->getAliasedOptions();
foreach ($options as $option => $value) {
if (isset($aliasOptions[$option])) {
// proxy alias -> option
$option = $aliasOptions[$option];
}
if (!in_array($option, $validOptions, true)) {
throw new \RuntimeException(sprintf('"%s" is not a valid column option.', $option));
}
$method = 'set' . ucfirst($option);
$this->$method($value);
}
return $this;
}
}
phinx-0.9.2/src/Phinx/Db/Table/ForeignKey.php 0000664 0000000 0000000 00000014042 13217376123 0020662 0 ustar 00root root 0000000 0000000
*/
namespace Phinx\Db\Table;
use Phinx\Db\Table;
class ForeignKey
{
const CASCADE = 'CASCADE';
const RESTRICT = 'RESTRICT';
const SET_NULL = 'SET NULL';
const NO_ACTION = 'NO ACTION';
/**
* @var array
*/
protected $columns = [];
/**
* @var \Phinx\Db\Table
*/
protected $referencedTable;
/**
* @var array
*/
protected $referencedColumns = [];
/**
* @var string
*/
protected $onDelete;
/**
* @var string
*/
protected $onUpdate;
/**
* @var string|boolean
*/
protected $constraint;
/**
* Sets the foreign key columns.
*
* @param array|string $columns
* @return \Phinx\Db\Table\ForeignKey
*/
public function setColumns($columns)
{
$this->columns = is_string($columns) ? [$columns] : $columns;
return $this;
}
/**
* Gets the foreign key columns.
*
* @return array
*/
public function getColumns()
{
return $this->columns;
}
/**
* Sets the foreign key referenced table.
*
* @param \Phinx\Db\Table $table
* @return \Phinx\Db\Table\ForeignKey
*/
public function setReferencedTable(Table $table)
{
$this->referencedTable = $table;
return $this;
}
/**
* Gets the foreign key referenced table.
*
* @return \Phinx\Db\Table
*/
public function getReferencedTable()
{
return $this->referencedTable;
}
/**
* Sets the foreign key referenced columns.
*
* @param array $referencedColumns
* @return \Phinx\Db\Table\ForeignKey
*/
public function setReferencedColumns(array $referencedColumns)
{
$this->referencedColumns = $referencedColumns;
return $this;
}
/**
* Gets the foreign key referenced columns.
*
* @return array
*/
public function getReferencedColumns()
{
return $this->referencedColumns;
}
/**
* Sets ON DELETE action for the foreign key.
*
* @param string $onDelete
* @return \Phinx\Db\Table\ForeignKey
*/
public function setOnDelete($onDelete)
{
$this->onDelete = $this->normalizeAction($onDelete);
return $this;
}
/**
* Gets ON DELETE action for the foreign key.
*
* @return string
*/
public function getOnDelete()
{
return $this->onDelete;
}
/**
* Gets ON UPDATE action for the foreign key.
*
* @return string
*/
public function getOnUpdate()
{
return $this->onUpdate;
}
/**
* Sets ON UPDATE action for the foreign key.
*
* @param string $onUpdate
* @return \Phinx\Db\Table\ForeignKey
*/
public function setOnUpdate($onUpdate)
{
$this->onUpdate = $this->normalizeAction($onUpdate);
return $this;
}
/**
* Sets constraint for the foreign key.
*
* @param string $constraint
* @return \Phinx\Db\Table\ForeignKey
*/
public function setConstraint($constraint)
{
$this->constraint = $constraint;
return $this;
}
/**
* Gets constraint name for the foreign key.
*
* @return string|bool
*/
public function getConstraint()
{
return $this->constraint;
}
/**
* Utility method that maps an array of index options to this objects methods.
*
* @param array $options Options
* @throws \RuntimeException
* @throws \InvalidArgumentException
* @return \Phinx\Db\Table\ForeignKey
*/
public function setOptions($options)
{
// Valid Options
$validOptions = ['delete', 'update', 'constraint'];
foreach ($options as $option => $value) {
if (!in_array($option, $validOptions, true)) {
throw new \RuntimeException(sprintf('"%s" is not a valid foreign key option.', $option));
}
// handle $options['delete'] as $options['update']
if ('delete' === $option) {
$this->setOnDelete($value);
} elseif ('update' === $option) {
$this->setOnUpdate($value);
} else {
$method = 'set' . ucfirst($option);
$this->$method($value);
}
}
return $this;
}
/**
* From passed value checks if it's correct and fixes if needed
*
* @param string $action
* @throws \InvalidArgumentException
* @return string
*/
protected function normalizeAction($action)
{
$constantName = 'static::' . str_replace(' ', '_', strtoupper(trim($action)));
if (!defined($constantName)) {
throw new \InvalidArgumentException('Unknown action passed: ' . $action);
}
return constant($constantName);
}
}
phinx-0.9.2/src/Phinx/Db/Table/Index.php 0000664 0000000 0000000 00000010013 13217376123 0017661 0 ustar 00root root 0000000 0000000 columns = $columns;
return $this;
}
/**
* Gets the index columns.
*
* @return array
*/
public function getColumns()
{
return $this->columns;
}
/**
* Sets the index type.
*
* @param string $type
* @return \Phinx\Db\Table\Index
*/
public function setType($type)
{
$this->type = $type;
return $this;
}
/**
* Gets the index type.
*
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Sets the index name.
*
* @param string $name
* @return \Phinx\Db\Table\Index
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Gets the index name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Sets the index limit.
*
* @param int $limit
* @return \Phinx\Db\Table\Index
*/
public function setLimit($limit)
{
$this->limit = $limit;
return $this;
}
/**
* Gets the index limit.
*
* @return int
*/
public function getLimit()
{
return $this->limit;
}
/**
* Utility method that maps an array of index options to this objects methods.
*
* @param array $options Options
* @throws \RuntimeException
* @return \Phinx\Db\Table\Index
*/
public function setOptions($options)
{
// Valid Options
$validOptions = ['type', 'unique', 'name', 'limit'];
foreach ($options as $option => $value) {
if (!in_array($option, $validOptions, true)) {
throw new \RuntimeException(sprintf('"%s" is not a valid index option.', $option));
}
// handle $options['unique']
if (strcasecmp($option, self::UNIQUE) === 0) {
if ((bool)$value) {
$this->setType(self::UNIQUE);
}
continue;
}
$method = 'set' . ucfirst($option);
$this->$method($value);
}
return $this;
}
}
phinx-0.9.2/src/Phinx/Migration/ 0000775 0000000 0000000 00000000000 13217376123 0016463 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Migration/AbstractMigration.php 0000664 0000000 0000000 00000014126 13217376123 0022615 0 ustar 00root root 0000000 0000000
*/
abstract class AbstractMigration implements MigrationInterface
{
/**
* @var float
*/
protected $version;
/**
* @var \Phinx\Db\Adapter\AdapterInterface
*/
protected $adapter;
/**
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;
/**
* @var \Symfony\Component\Console\Input\InputInterface
*/
protected $input;
/**
* Whether this migration is being applied or reverted
*
* @var bool
*/
protected $isMigratingUp = true;
/**
* Class Constructor.
*
* @param int $version Migration Version
* @param \Symfony\Component\Console\Input\InputInterface|null $input
* @param \Symfony\Component\Console\Output\OutputInterface|null $output
*/
final public function __construct($version, InputInterface $input = null, OutputInterface $output = null)
{
$this->version = $version;
if (!is_null($input)) {
$this->setInput($input);
}
if (!is_null($output)) {
$this->setOutput($output);
}
$this->init();
}
/**
* Initialize method.
*
* @return void
*/
protected function init()
{
}
/**
* {@inheritdoc}
*/
public function up()
{
}
/**
* {@inheritdoc}
*/
public function down()
{
}
/**
* {@inheritdoc}
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* {@inheritdoc}
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* {@inheritdoc}
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* {@inheritdoc}
*/
public function getInput()
{
return $this->input;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
return $this->output;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return get_class($this);
}
/**
* {@inheritdoc}
*/
public function setVersion($version)
{
$this->version = $version;
return $this;
}
/**
* {@inheritdoc}
*/
public function getVersion()
{
return $this->version;
}
/**
* {@inheritdoc}
*/
public function setMigratingUp($isMigratingUp)
{
$this->isMigratingUp = $isMigratingUp;
return $this;
}
/**
* {@inheritdoc}
*/
public function isMigratingUp()
{
return $this->isMigratingUp;
}
/**
* {@inheritdoc}
*/
public function execute($sql)
{
return $this->getAdapter()->execute($sql);
}
/**
* {@inheritdoc}
*/
public function query($sql)
{
return $this->getAdapter()->query($sql);
}
/**
* {@inheritdoc}
*/
public function fetchRow($sql)
{
return $this->getAdapter()->fetchRow($sql);
}
/**
* {@inheritdoc}
*/
public function fetchAll($sql)
{
return $this->getAdapter()->fetchAll($sql);
}
/**
* {@inheritdoc}
*/
public function insert($table, $data)
{
// convert to table object
if (is_string($table)) {
$table = new Table($table, [], $this->getAdapter());
}
$table->insert($data)->save();
}
/**
* {@inheritdoc}
*/
public function createDatabase($name, $options)
{
$this->getAdapter()->createDatabase($name, $options);
}
/**
* {@inheritdoc}
*/
public function dropDatabase($name)
{
$this->getAdapter()->dropDatabase($name);
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
return $this->getAdapter()->hasTable($tableName);
}
/**
* {@inheritdoc}
*/
public function table($tableName, $options = [])
{
return new Table($tableName, $options, $this->getAdapter());
}
/**
* A short-hand method to drop the given database table.
*
* @param string $tableName Table Name
* @return void
*/
public function dropTable($tableName)
{
$this->table($tableName)->drop();
}
}
phinx-0.9.2/src/Phinx/Migration/AbstractTemplateCreation.php 0000664 0000000 0000000 00000005104 13217376123 0024120 0 ustar 00root root 0000000 0000000 setInput($input);
}
if (!is_null($output)) {
$this->setOutput($output);
}
}
/**
* {@inheritdoc}
*/
public function getInput()
{
return $this->input;
}
/**
* {@inheritdoc}
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
return $this->output;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
}
phinx-0.9.2/src/Phinx/Migration/CreationInterface.php 0000664 0000000 0000000 00000006203 13217376123 0022562 0 ustar 00root root 0000000 0000000
*/
interface CreationInterface
{
/**
* CreationInterface constructor.
*
* @param \Symfony\Component\Console\Input\InputInterface|null $input
* @param \Symfony\Component\Console\Output\OutputInterface|null $output
*/
public function __construct(InputInterface $input = null, OutputInterface $output = null);
/**
* @param \Symfony\Component\Console\Input\InputInterface $input
*
* @return \Phinx\Migration\CreationInterface
*/
public function setInput(InputInterface $input);
/**
* @param \Symfony\Component\Console\Output\OutputInterface $output
*
* @return \Phinx\Migration\CreationInterface
*/
public function setOutput(OutputInterface $output);
/**
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput();
/**
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput();
/**
* Get the migration template.
*
* This will be the content that Phinx will amend to generate the migration file.
*
* @return string The content of the template for Phinx to amend.
*/
public function getMigrationTemplate();
/**
* Post Migration Creation.
*
* Once the migration file has been created, this method will be called, allowing any additional
* processing, specific to the template to be performed.
*
* @param string $migrationFilename The name of the newly created migration.
* @param string $className The class name.
* @param string $baseClassName The name of the base class.
* @return void
*/
public function postMigrationCreation($migrationFilename, $className, $baseClassName);
}
phinx-0.9.2/src/Phinx/Migration/IrreversibleMigrationException.php 0000664 0000000 0000000 00000002644 13217376123 0025370 0 ustar 00root root 0000000 0000000
*/
class IrreversibleMigrationException extends \Exception
{
}
phinx-0.9.2/src/Phinx/Migration/Manager.php 0000664 0000000 0000000 00000102263 13217376123 0020552 0 ustar 00root root 0000000 0000000 setConfig($config);
$this->setInput($input);
$this->setOutput($output);
}
/**
* Prints the specified environment's migration status.
*
* @param string $environment
* @param null $format
* @return int 0 if all migrations are up, or an error code
*/
public function printStatus($environment, $format = null)
{
$output = $this->getOutput();
$migrations = [];
$hasDownMigration = false;
$hasMissingMigration = false;
$migrations = $this->getMigrations();
if (count($migrations)) {
// TODO - rewrite using Symfony Table Helper as we already have this library
// included and it will fix formatting issues (e.g drawing the lines)
$output->writeln('');
switch ($this->getConfig()->getVersionOrder()) {
case \Phinx\Config\Config::VERSION_ORDER_CREATION_TIME:
$migrationIdAndStartedHeader = "[Migration ID] Started ";
break;
case \Phinx\Config\Config::VERSION_ORDER_EXECUTION_TIME:
$migrationIdAndStartedHeader = "Migration ID [Started ]";
break;
default:
throw new \RuntimeException('Invalid version_order configuration option');
}
$output->writeln(" Status $migrationIdAndStartedHeader Finished Migration Name ");
$output->writeln('----------------------------------------------------------------------------------');
$env = $this->getEnvironment($environment);
$versions = $env->getVersionLog();
$maxNameLength = $versions ? max(array_map(function ($version) {
return strlen($version['migration_name']);
}, $versions)) : 0;
$missingVersions = array_diff_key($versions, $migrations);
$hasMissingMigration = !empty($missingVersions);
// get the migrations sorted in the same way as the versions
$sortedMigrations = [];
foreach ($versions as $versionCreationTime => $version) {
if (isset($migrations[$versionCreationTime])) {
array_push($sortedMigrations, $migrations[$versionCreationTime]);
unset($migrations[$versionCreationTime]);
}
}
if (empty($sortedMigrations) && !empty($missingVersions)) {
// this means we have no up migrations, so we write all the missing versions already so they show up
// before any possible down migration
foreach ($missingVersions as $missingVersionCreationTime => $missingVersion) {
$this->printMissingVersion($missingVersion, $maxNameLength);
unset($missingVersions[$missingVersionCreationTime]);
}
}
// any migration left in the migrations (ie. not unset when sorting the migrations by the version order) is
// a migration that is down, so we add them to the end of the sorted migrations list
if (!empty($migrations)) {
$sortedMigrations = array_merge($sortedMigrations, $migrations);
}
foreach ($sortedMigrations as $migration) {
$version = array_key_exists($migration->getVersion(), $versions) ? $versions[$migration->getVersion()] : false;
if ($version) {
// check if there are missing versions before this version
foreach ($missingVersions as $missingVersionCreationTime => $missingVersion) {
if ($this->getConfig()->isVersionOrderCreationTime()) {
if ($missingVersion['version'] > $version['version']) {
break;
}
} else {
if ($missingVersion['start_time'] > $version['start_time']) {
break;
} elseif ($missingVersion['start_time'] == $version['start_time'] &&
$missingVersion['version'] > $version['version']) {
break;
}
}
$this->printMissingVersion($missingVersion, $maxNameLength);
unset($missingVersions[$missingVersionCreationTime]);
}
$status = ' up ';
} else {
$hasDownMigration = true;
$status = ' down ';
}
$maxNameLength = max($maxNameLength, strlen($migration->getName()));
$output->writeln(sprintf(
'%s %14.0f %19s %19s %s',
$status,
$migration->getVersion(),
$version['start_time'],
$version['end_time'],
$migration->getName()
));
if ($version && $version['breakpoint']) {
$output->writeln(' BREAKPOINT SET');
}
$migrations[] = ['migration_status' => trim(strip_tags($status)), 'migration_id' => sprintf('%14.0f', $migration->getVersion()), 'migration_name' => $migration->getName()];
unset($versions[$migration->getVersion()]);
}
// and finally add any possibly-remaining missing migrations
foreach ($missingVersions as $missingVersionCreationTime => $missingVersion) {
$this->printMissingVersion($missingVersion, $maxNameLength);
unset($missingVersions[$missingVersionCreationTime]);
}
} else {
// there are no migrations
$output->writeln('');
$output->writeln('There are no available migrations. Try creating one using the create command.');
}
// write an empty line
$output->writeln('');
if ($format !== null) {
switch ($format) {
case 'json':
$output->writeln(json_encode(
[
'pending_count' => count($this->getMigrations()),
'migrations' => $migrations
]
));
break;
default:
$output->writeln('Unsupported format: ' . $format . '');
}
}
if ($hasMissingMigration) {
return self::EXIT_STATUS_MISSING;
} elseif ($hasDownMigration) {
return self::EXIT_STATUS_DOWN;
} else {
return 0;
}
}
/**
* Print Missing Version
*
* @param array $version The missing version to print (in the format returned by Environment.getVersionLog).
* @param int $maxNameLength The maximum migration name length.
*/
private function printMissingVersion($version, $maxNameLength)
{
$this->getOutput()->writeln(sprintf(
' up %14.0f %19s %19s %s ** MISSING **',
$version['version'],
$version['start_time'],
$version['end_time'],
str_pad($version['migration_name'], $maxNameLength, ' ')
));
if ($version && $version['breakpoint']) {
$this->getOutput()->writeln(' BREAKPOINT SET');
}
}
/**
* Migrate to the version of the database on a given date.
*
* @param string $environment Environment
* @param \DateTime $dateTime Date to migrate to
*
* @return void
*/
public function migrateToDateTime($environment, \DateTime $dateTime)
{
$versions = array_keys($this->getMigrations());
$dateString = $dateTime->format('YmdHis');
$outstandingMigrations = array_filter($versions, function ($version) use ($dateString) {
return $version <= $dateString;
});
if (count($outstandingMigrations) > 0) {
$migration = max($outstandingMigrations);
$this->getOutput()->writeln('Migrating to version ' . $migration);
$this->migrate($environment, $migration);
}
}
/**
* Migrate an environment to the specified version.
*
* @param string $environment Environment
* @param int $version
* @return void
*/
public function migrate($environment, $version = null)
{
$migrations = $this->getMigrations();
$env = $this->getEnvironment($environment);
$versions = $env->getVersions();
$current = $env->getCurrentVersion();
if (empty($versions) && empty($migrations)) {
return;
}
if ($version === null) {
$version = max(array_merge($versions, array_keys($migrations)));
} else {
if (0 != $version && !isset($migrations[$version])) {
$this->output->writeln(sprintf(
'warning %s is not a valid version',
$version
));
return;
}
}
// are we migrating up or down?
$direction = $version > $current ? MigrationInterface::UP : MigrationInterface::DOWN;
if ($direction === MigrationInterface::DOWN) {
// run downs first
krsort($migrations);
foreach ($migrations as $migration) {
if ($migration->getVersion() <= $version) {
break;
}
if (in_array($migration->getVersion(), $versions)) {
$this->executeMigration($environment, $migration, MigrationInterface::DOWN);
}
}
}
ksort($migrations);
foreach ($migrations as $migration) {
if ($migration->getVersion() > $version) {
break;
}
if (!in_array($migration->getVersion(), $versions)) {
$this->executeMigration($environment, $migration, MigrationInterface::UP);
}
}
}
/**
* Execute a migration against the specified environment.
*
* @param string $name Environment Name
* @param \Phinx\Migration\MigrationInterface $migration Migration
* @param string $direction Direction
* @return void
*/
public function executeMigration($name, MigrationInterface $migration, $direction = MigrationInterface::UP)
{
$this->getOutput()->writeln('');
$this->getOutput()->writeln(
' ==' .
' ' . $migration->getVersion() . ' ' . $migration->getName() . ':' .
' ' . ($direction === MigrationInterface::UP ? 'migrating' : 'reverting') . ''
);
// Execute the migration and log the time elapsed.
$start = microtime(true);
$this->getEnvironment($name)->executeMigration($migration, $direction);
$end = microtime(true);
$this->getOutput()->writeln(
' ==' .
' ' . $migration->getVersion() . ' ' . $migration->getName() . ':' .
' ' . ($direction === MigrationInterface::UP ? 'migrated' : 'reverted') .
' ' . sprintf('%.4fs', $end - $start) . ''
);
}
/**
* Execute a seeder against the specified environment.
*
* @param string $name Environment Name
* @param \Phinx\Seed\SeedInterface $seed Seed
* @return void
*/
public function executeSeed($name, SeedInterface $seed)
{
$this->getOutput()->writeln('');
$this->getOutput()->writeln(
' ==' .
' ' . $seed->getName() . ':' .
' seeding'
);
// Execute the seeder and log the time elapsed.
$start = microtime(true);
$this->getEnvironment($name)->executeSeed($seed);
$end = microtime(true);
$this->getOutput()->writeln(
' ==' .
' ' . $seed->getName() . ':' .
' seeded' .
' ' . sprintf('%.4fs', $end - $start) . ''
);
}
/**
* Rollback an environment to the specified version.
*
* @param string $environment Environment
* @param int|string $target
* @param bool $force
* @param bool $targetMustMatchVersion
* @return void
*/
public function rollback($environment, $target = null, $force = false, $targetMustMatchVersion = true)
{
// note that the migrations are indexed by name (aka creation time) in ascending order
$migrations = $this->getMigrations();
// note that the version log are also indexed by name with the proper ascending order according to the version order
$executedVersions = $this->getEnvironment($environment)->getVersionLog();
// get a list of migrations sorted in the opposite way of the executed versions
$sortedMigrations = [];
foreach ($executedVersions as $versionCreationTime => &$executedVersion) {
// if we have a date (ie. the target must not match a version) and we are sorting by execution time, we
// convert the version start time so we can compare directly with the target date
if (!$this->getConfig()->isVersionOrderCreationTime() && !$targetMustMatchVersion) {
$dateTime = \DateTime::createFromFormat('Y-m-d H:i:s', $executedVersion['start_time']);
$executedVersion['start_time'] = $dateTime->format('YmdHis');
}
if (isset($migrations[$versionCreationTime])) {
array_unshift($sortedMigrations, $migrations[$versionCreationTime]);
} else {
// this means the version is missing so we unset it so that we don't consider it when rolling back
// migrations (or choosing the last up version as target)
unset($executedVersions[$versionCreationTime]);
}
}
if ($target === 'all' || $target === '0') {
$target = 0;
} elseif (!is_numeric($target) && !is_null($target)) { // try to find a target version based on name
// search through the migrations using the name
$migrationNames = array_map(function ($item) {
return $item['migration_name'];
}, $executedVersions);
$found = array_search($target, $migrationNames);
// check on was found
if ($found !== false) {
$target = (string)$found;
} else {
$this->getOutput()->writeln("No migration found with name ($target)");
return;
}
}
// Check we have at least 1 migration to revert
$executedVersionCreationTimes = array_keys($executedVersions);
if (empty($executedVersionCreationTimes) || $target == end($executedVersionCreationTimes)) {
$this->getOutput()->writeln('No migrations to rollback');
return;
}
// If no target was supplied, revert the last migration
if ($target === null) {
// Get the migration before the last run migration
$prev = count($executedVersionCreationTimes) - 2;
$target = $prev >= 0 ? $executedVersionCreationTimes[$prev] : 0;
}
// If the target must match a version, check the target version exists
if ($targetMustMatchVersion && 0 !== $target && !isset($migrations[$target])) {
$this->getOutput()->writeln("Target version ($target) not found");
return;
}
// Rollback all versions until we find the wanted rollback target
$rollbacked = false;
foreach ($sortedMigrations as $migration) {
if ($targetMustMatchVersion && $migration->getVersion() == $target) {
break;
}
if (in_array($migration->getVersion(), $executedVersionCreationTimes)) {
$executedVersion = $executedVersions[$migration->getVersion()];
if (!$targetMustMatchVersion) {
if (($this->getConfig()->isVersionOrderCreationTime() && $executedVersion['version'] <= $target) ||
(!$this->getConfig()->isVersionOrderCreationTime() && $executedVersion['start_time'] <= $target)) {
break;
}
}
if (0 != $executedVersion['breakpoint'] && !$force) {
$this->getOutput()->writeln('Breakpoint reached. Further rollbacks inhibited.');
break;
}
$this->executeMigration($environment, $migration, MigrationInterface::DOWN);
$rollbacked = true;
}
}
if (!$rollbacked) {
$this->getOutput()->writeln('No migrations to rollback');
}
}
/**
* Run database seeders against an environment.
*
* @param string $environment Environment
* @param string $seed Seeder
* @return void
*/
public function seed($environment, $seed = null)
{
$seeds = $this->getSeeds();
if ($seed === null) {
// run all seeders
foreach ($seeds as $seeder) {
if (array_key_exists($seeder->getName(), $seeds)) {
$this->executeSeed($environment, $seeder);
}
}
} else {
// run only one seeder
if (array_key_exists($seed, $seeds)) {
$this->executeSeed($environment, $seeds[$seed]);
} else {
throw new \InvalidArgumentException(sprintf('The seed class "%s" does not exist', $seed));
}
}
}
/**
* Sets the environments.
*
* @param array $environments Environments
* @return \Phinx\Migration\Manager
*/
public function setEnvironments($environments = [])
{
$this->environments = $environments;
return $this;
}
/**
* Gets the manager class for the given environment.
*
* @param string $name Environment Name
* @throws \InvalidArgumentException
* @return \Phinx\Migration\Manager\Environment
*/
public function getEnvironment($name)
{
if (isset($this->environments[$name])) {
return $this->environments[$name];
}
// check the environment exists
if (!$this->getConfig()->hasEnvironment($name)) {
throw new \InvalidArgumentException(sprintf(
'The environment "%s" does not exist',
$name
));
}
// create an environment instance and cache it
$envOptions = $this->getConfig()->getEnvironment($name);
$envOptions['version_order'] = $this->getConfig()->getVersionOrder();
$environment = new Environment($name, $envOptions);
$this->environments[$name] = $environment;
$environment->setInput($this->getInput());
$environment->setOutput($this->getOutput());
return $environment;
}
/**
* Sets the console input.
*
* @param \Symfony\Component\Console\Input\InputInterface $input Input
* @return \Phinx\Migration\Manager
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* Gets the console input.
*
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput()
{
return $this->input;
}
/**
* Sets the console output.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output Output
* @return \Phinx\Migration\Manager
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
/**
* Gets the console output.
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput()
{
return $this->output;
}
/**
* Sets the database migrations.
*
* @param array $migrations Migrations
* @return \Phinx\Migration\Manager
*/
public function setMigrations(array $migrations)
{
$this->migrations = $migrations;
return $this;
}
/**
* Gets an array of the database migrations, indexed by migration name (aka creation time) and sorted in ascending
* order
*
* @throws \InvalidArgumentException
* @return \Phinx\Migration\AbstractMigration[]
*/
public function getMigrations()
{
if ($this->migrations === null) {
$phpFiles = $this->getMigrationFiles();
// filter the files to only get the ones that match our naming scheme
$fileNames = [];
/** @var \Phinx\Migration\AbstractMigration[] $versions */
$versions = [];
foreach ($phpFiles as $filePath) {
if (Util::isValidMigrationFileName(basename($filePath))) {
$version = Util::getVersionFromFileName(basename($filePath));
if (isset($versions[$version])) {
throw new \InvalidArgumentException(sprintf('Duplicate migration - "%s" has the same version as "%s"', $filePath, $versions[$version]->getVersion()));
}
$config = $this->getConfig();
$namespace = $config instanceof NamespaceAwareInterface ? $config->getMigrationNamespaceByPath(dirname($filePath)) : null;
// convert the filename to a class name
$class = ($namespace === null ? '' : $namespace . '\\') . Util::mapFileNameToClassName(basename($filePath));
if (isset($fileNames[$class])) {
throw new \InvalidArgumentException(sprintf(
'Migration "%s" has the same name as "%s"',
basename($filePath),
$fileNames[$class]
));
}
$fileNames[$class] = basename($filePath);
// load the migration file
/** @noinspection PhpIncludeInspection */
require_once $filePath;
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf(
'Could not find class "%s" in file "%s"',
$class,
$filePath
));
}
// instantiate it
$migration = new $class($version, $this->getInput(), $this->getOutput());
if (!($migration instanceof AbstractMigration)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" in file "%s" must extend \Phinx\Migration\AbstractMigration',
$class,
$filePath
));
}
$versions[$version] = $migration;
}
}
ksort($versions);
$this->setMigrations($versions);
}
return $this->migrations;
}
/**
* Returns a list of migration files found in the provided migration paths.
*
* @return string[]
*/
protected function getMigrationFiles()
{
$config = $this->getConfig();
$paths = $config->getMigrationPaths();
$files = [];
foreach ($paths as $path) {
$files = array_merge(
$files,
Util::glob($path . DIRECTORY_SEPARATOR . '*.php')
);
}
// glob() can return the same file multiple times
// This will cause the migration to fail with a
// false assumption of duplicate migrations
// http://php.net/manual/en/function.glob.php#110340
$files = array_unique($files);
return $files;
}
/**
* Sets the database seeders.
*
* @param array $seeds Seeders
* @return \Phinx\Migration\Manager
*/
public function setSeeds(array $seeds)
{
$this->seeds = $seeds;
return $this;
}
/**
* Get seed dependencies instances from seed dependency array
*
* @param AbstractSeed $seed Seed
*
* @return AbstractSeed[]
*/
private function getSeedDependenciesInstances(AbstractSeed $seed)
{
$dependenciesInstances = [];
$dependencies = $seed->getDependencies();
if (!empty($dependencies)) {
foreach ($dependencies as $dependency) {
foreach ($this->seeds as $seed) {
if (get_class($seed) === $dependency) {
$dependenciesInstances[get_class($seed)] = $seed;
}
}
}
}
return $dependenciesInstances;
}
/**
* Order seeds by dependencies
*
* @param AbstractSeed[] $seeds Seeds
*
* @return AbstractSeed[]
*/
private function orderSeedsByDependencies(array $seeds)
{
$orderedSeeds = [];
foreach ($seeds as $seed) {
$key = get_class($seed);
$dependencies = $this->getSeedDependenciesInstances($seed);
if (!empty($dependencies)) {
$orderedSeeds[$key] = $seed;
$orderedSeeds = array_merge($this->orderSeedsByDependencies($dependencies), $orderedSeeds);
} else {
$orderedSeeds[$key] = $seed;
}
}
return $orderedSeeds;
}
/**
* Gets an array of database seeders.
*
* @throws \InvalidArgumentException
* @return \Phinx\Seed\AbstractSeed[]
*/
public function getSeeds()
{
if ($this->seeds === null) {
$phpFiles = $this->getSeedFiles();
// filter the files to only get the ones that match our naming scheme
$fileNames = [];
/** @var \Phinx\Seed\AbstractSeed[] $seeds */
$seeds = [];
foreach ($phpFiles as $filePath) {
if (Util::isValidSeedFileName(basename($filePath))) {
$config = $this->getConfig();
$namespace = $config instanceof NamespaceAwareInterface ? $config->getSeedNamespaceByPath(dirname($filePath)) : null;
// convert the filename to a class name
$class = ($namespace === null ? '' : $namespace . '\\') . pathinfo($filePath, PATHINFO_FILENAME);
$fileNames[$class] = basename($filePath);
// load the seed file
/** @noinspection PhpIncludeInspection */
require_once $filePath;
if (!class_exists($class)) {
throw new \InvalidArgumentException(sprintf(
'Could not find class "%s" in file "%s"',
$class,
$filePath
));
}
// instantiate it
$seed = new $class($this->getInput(), $this->getOutput());
if (!($seed instanceof AbstractSeed)) {
throw new \InvalidArgumentException(sprintf(
'The class "%s" in file "%s" must extend \Phinx\Seed\AbstractSeed',
$class,
$filePath
));
}
$seeds[$class] = $seed;
}
}
ksort($seeds);
$this->setSeeds($seeds);
}
$this->seeds = $this->orderSeedsByDependencies($this->seeds);
return $this->seeds;
}
/**
* Returns a list of seed files found in the provided seed paths.
*
* @return string[]
*/
protected function getSeedFiles()
{
$config = $this->getConfig();
$paths = $config->getSeedPaths();
$files = [];
foreach ($paths as $path) {
$files = array_merge(
$files,
Util::glob($path . DIRECTORY_SEPARATOR . '*.php')
);
}
// glob() can return the same file multiple times
// This will cause the migration to fail with a
// false assumption of duplicate migrations
// http://php.net/manual/en/function.glob.php#110340
$files = array_unique($files);
return $files;
}
/**
* Sets the config.
*
* @param \Phinx\Config\ConfigInterface $config Configuration Object
* @return \Phinx\Migration\Manager
*/
public function setConfig(ConfigInterface $config)
{
$this->config = $config;
return $this;
}
/**
* Gets the config.
*
* @return \Phinx\Config\ConfigInterface
*/
public function getConfig()
{
return $this->config;
}
/**
* Toggles the breakpoint for a specific version.
*
* @param string $environment
* @param int $version
* @return void
*/
public function toggleBreakpoint($environment, $version)
{
$migrations = $this->getMigrations();
$this->getMigrations();
$env = $this->getEnvironment($environment);
$versions = $env->getVersionLog();
if (empty($versions) || empty($migrations)) {
return;
}
if ($version === null) {
$lastVersion = end($versions);
$version = $lastVersion['version'];
}
if (0 != $version && !isset($migrations[$version])) {
$this->output->writeln(sprintf(
'warning %s is not a valid version',
$version
));
return;
}
$env->getAdapter()->toggleBreakpoint($migrations[$version]);
$versions = $env->getVersionLog();
$this->getOutput()->writeln(
' Breakpoint ' . ($versions[$version]['breakpoint'] ? 'set' : 'cleared') .
' for ' . $version . '' .
' ' . $migrations[$version]->getName() . ''
);
}
/**
* Remove all breakpoints
*
* @param string $environment
* @return void
*/
public function removeBreakpoints($environment)
{
$this->getOutput()->writeln(sprintf(
' %d breakpoints cleared.',
$this->getEnvironment($environment)->getAdapter()->resetAllBreakpoints()
));
}
}
phinx-0.9.2/src/Phinx/Migration/Manager/ 0000775 0000000 0000000 00000000000 13217376123 0020035 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Migration/Manager/Environment.php 0000664 0000000 0000000 00000025442 13217376123 0023061 0 ustar 00root root 0000000 0000000 name = $name;
$this->options = $options;
}
/**
* Executes the specified migration on this environment.
*
* @param \Phinx\Migration\MigrationInterface $migration Migration
* @param string $direction Direction
* @return void
*/
public function executeMigration(MigrationInterface $migration, $direction = MigrationInterface::UP)
{
$direction = ($direction === MigrationInterface::UP) ? MigrationInterface::UP : MigrationInterface::DOWN;
$migration->setMigratingUp($direction === MigrationInterface::UP);
$startTime = time();
$migration->setAdapter($this->getAdapter());
// begin the transaction if the adapter supports it
if ($this->getAdapter()->hasTransactions()) {
$this->getAdapter()->beginTransaction();
}
// Run the migration
if (method_exists($migration, MigrationInterface::CHANGE)) {
if ($direction === MigrationInterface::DOWN) {
// Create an instance of the ProxyAdapter so we can record all
// of the migration commands for reverse playback
/** @var \Phinx\Db\Adapter\ProxyAdapter $proxyAdapter */
$proxyAdapter = AdapterFactory::instance()
->getWrapper('proxy', $this->getAdapter());
$migration->setAdapter($proxyAdapter);
/** @noinspection PhpUndefinedMethodInspection */
$migration->change();
$proxyAdapter->executeInvertedCommands();
$migration->setAdapter($this->getAdapter());
} else {
/** @noinspection PhpUndefinedMethodInspection */
$migration->change();
}
} else {
$migration->{$direction}();
}
// commit the transaction if the adapter supports it
if ($this->getAdapter()->hasTransactions()) {
$this->getAdapter()->commitTransaction();
}
// Record it in the database
$this->getAdapter()->migrated($migration, $direction, date('Y-m-d H:i:s', $startTime), date('Y-m-d H:i:s', time()));
}
/**
* Executes the specified seeder on this environment.
*
* @param \Phinx\Seed\SeedInterface $seed
* @return void
*/
public function executeSeed(SeedInterface $seed)
{
$seed->setAdapter($this->getAdapter());
// begin the transaction if the adapter supports it
if ($this->getAdapter()->hasTransactions()) {
$this->getAdapter()->beginTransaction();
}
// Run the seeder
if (method_exists($seed, SeedInterface::RUN)) {
$seed->run();
}
// commit the transaction if the adapter supports it
if ($this->getAdapter()->hasTransactions()) {
$this->getAdapter()->commitTransaction();
}
}
/**
* Sets the environment's name.
*
* @param string $name Environment Name
* @return \Phinx\Migration\Manager\Environment
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Gets the environment name.
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Sets the environment's options.
*
* @param array $options Environment Options
* @return \Phinx\Migration\Manager\Environment
*/
public function setOptions($options)
{
$this->options = $options;
return $this;
}
/**
* Gets the environment's options.
*
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* Sets the console input.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @return \Phinx\Migration\Manager\Environment
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* Gets the console input.
*
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput()
{
return $this->input;
}
/**
* Sets the console output.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output Output
* @return \Phinx\Migration\Manager\Environment
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
/**
* Gets the console output.
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput()
{
return $this->output;
}
/**
* Gets all migrated version numbers.
*
* @return array
*/
public function getVersions()
{
return $this->getAdapter()->getVersions();
}
/**
* Get all migration log entries, indexed by version creation time and sorted ascendingly by the configuration's
* version_order option
*
* @return array
*/
public function getVersionLog()
{
return $this->getAdapter()->getVersionLog();
}
/**
* Sets the current version of the environment.
*
* @param int $version Environment Version
* @return \Phinx\Migration\Manager\Environment
*/
public function setCurrentVersion($version)
{
$this->currentVersion = $version;
return $this;
}
/**
* Gets the current version of the environment.
*
* @return int
*/
public function getCurrentVersion()
{
// We don't cache this code as the current version is pretty volatile.
// TODO - that means they're no point in a setter then?
// maybe we should cache and call a reset() method everytime a migration is run
$versions = $this->getVersions();
$version = 0;
if (!empty($versions)) {
$version = end($versions);
}
$this->setCurrentVersion($version);
return $this->currentVersion;
}
/**
* Sets the database adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
* @return \Phinx\Migration\Manager\Environment
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* Gets the database adapter.
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter()
{
if (isset($this->adapter)) {
return $this->adapter;
}
if (isset($this->options['connection'])) {
if (!($this->options['connection'] instanceof \PDO)) {
throw new \RuntimeException('The specified connection is not a PDO instance');
}
$this->options['connection']->setAttribute(\PDO::ATTR_ERRMODE, \PDO::ERRMODE_EXCEPTION);
$this->options['adapter'] = $this->options['connection']->getAttribute(\PDO::ATTR_DRIVER_NAME);
}
if (!isset($this->options['adapter'])) {
throw new \RuntimeException('No adapter was specified for environment: ' . $this->getName());
}
$factory = AdapterFactory::instance();
$adapter = $factory
->getAdapter($this->options['adapter'], $this->options);
// Automatically time the executed commands
$adapter = $factory->getWrapper('timed', $adapter);
if (isset($this->options['wrapper'])) {
$adapter = $factory
->getWrapper($this->options['wrapper'], $adapter);
}
if ($this->getInput()) {
$adapter->setInput($this->getInput());
}
if ($this->getOutput()) {
$adapter->setOutput($this->getOutput());
}
// Use the TablePrefixAdapter if table prefix/suffixes are in use
if ($adapter->hasOption('table_prefix') || $adapter->hasOption('table_suffix')) {
$adapter = AdapterFactory::instance()
->getWrapper('prefix', $adapter);
}
$this->setAdapter($adapter);
return $adapter;
}
/**
* Sets the schema table name.
*
* @param string $schemaTableName Schema Table Name
* @return \Phinx\Migration\Manager\Environment
*/
public function setSchemaTableName($schemaTableName)
{
$this->schemaTableName = $schemaTableName;
return $this;
}
/**
* Gets the schema table name.
*
* @return string
*/
public function getSchemaTableName()
{
return $this->schemaTableName;
}
}
phinx-0.9.2/src/Phinx/Migration/Migration.template.php.dist 0000664 0000000 0000000 00000001411 13217376123 0023676 0 ustar 00root root 0000000 0000000
*/
interface MigrationInterface
{
/**
* @var string
*/
const CHANGE = 'change';
/**
* @var string
*/
const UP = 'up';
/**
* @var string
*/
const DOWN = 'down';
/**
* Migrate Up
*
* @return void
*/
public function up();
/**
* Migrate Down
*
* @return void
*/
public function down();
/**
* Sets the database adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
* @return \Phinx\Migration\MigrationInterface
*/
public function setAdapter(AdapterInterface $adapter);
/**
* Gets the database adapter.
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter();
/**
* Sets the input object to be used in migration object
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @return \Phinx\Migration\MigrationInterface
*/
public function setInput(InputInterface $input);
/**
* Gets the input object to be used in migration object
*
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput();
/**
* Sets the output object to be used in migration object
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return \Phinx\Migration\MigrationInterface
*/
public function setOutput(OutputInterface $output);
/**
* Gets the output object to be used in migration object
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput();
/**
* Gets the name.
*
* @return string
*/
public function getName();
/**
* Sets the migration version number.
*
* @param float $version Version
* @return \Phinx\Migration\MigrationInterface
*/
public function setVersion($version);
/**
* Gets the migration version number.
*
* @return float
*/
public function getVersion();
/**
* Sets whether this migration is being applied or reverted
*
* @param bool $isMigratingUp True if the migration is being applied
* @return \Phinx\Migration\MigrationInterface
*/
public function setMigratingUp($isMigratingUp);
/**
* Gets whether this migration is being applied or reverted.
* True means that the migration is being applied.
*
* @return bool
*/
public function isMigratingUp();
/**
* Executes a SQL statement and returns the number of affected rows.
*
* @param string $sql SQL
* @return int
*/
public function execute($sql);
/**
* Executes a SQL statement and returns the result as an array.
*
* @param string $sql SQL
* @return array
*/
public function query($sql);
/**
* Executes a query and returns only one row as an array.
*
* @param string $sql SQL
* @return array
*/
public function fetchRow($sql);
/**
* Executes a query and returns an array of rows.
*
* @param string $sql SQL
* @return array
*/
public function fetchAll($sql);
/**
* Insert data into a table.
*
* @param string $tableName
* @param array $data
* @return void
*/
public function insert($tableName, $data);
/**
* Create a new database.
*
* @param string $name Database Name
* @param array $options Options
* @return void
*/
public function createDatabase($name, $options);
/**
* Drop a database.
*
* @param string $name Database Name
* @return void
*/
public function dropDatabase($name);
/**
* Checks to see if a table exists.
*
* @param string $tableName Table Name
* @return bool
*/
public function hasTable($tableName);
/**
* Returns an instance of the \Table
class.
*
* You can use this class to create and manipulate tables.
*
* @param string $tableName Table Name
* @param array $options Options
* @return \Phinx\Db\Table
*/
public function table($tableName, $options);
}
phinx-0.9.2/src/Phinx/Seed/ 0000775 0000000 0000000 00000000000 13217376123 0015412 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Seed/AbstractSeed.php 0000664 0000000 0000000 00000011407 13217376123 0020472 0 ustar 00root root 0000000 0000000
*/
abstract class AbstractSeed implements SeedInterface
{
/**
* @var \Phinx\Db\Adapter\AdapterInterface
*/
protected $adapter;
/**
* @var \Symfony\Component\Console\Input\InputInterface
*/
protected $input;
/**
* @var \Symfony\Component\Console\Output\OutputInterface
*/
protected $output;
/**
* Class Constructor.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
*/
final public function __construct(InputInterface $input = null, OutputInterface $output = null)
{
if (!is_null($input)) {
$this->setInput($input);
}
if (!is_null($output)) {
$this->setOutput($output);
}
$this->init();
}
/**
* Initialize method.
*
* @return void
*/
protected function init()
{
}
/**
* {@inheritdoc}
*/
public function run()
{
}
/**
* Return seeds dependencies.
*
* @return array
*/
public function getDependencies()
{
return [];
}
/**
* {@inheritdoc}
*/
public function setAdapter(AdapterInterface $adapter)
{
$this->adapter = $adapter;
return $this;
}
/**
* {@inheritdoc}
*/
public function getAdapter()
{
return $this->adapter;
}
/**
* {@inheritdoc}
*/
public function setInput(InputInterface $input)
{
$this->input = $input;
return $this;
}
/**
* {@inheritdoc}
*/
public function getInput()
{
return $this->input;
}
/**
* {@inheritdoc}
*/
public function setOutput(OutputInterface $output)
{
$this->output = $output;
return $this;
}
/**
* {@inheritdoc}
*/
public function getOutput()
{
return $this->output;
}
/**
* {@inheritdoc}
*/
public function getName()
{
return get_class($this);
}
/**
* {@inheritdoc}
*/
public function execute($sql)
{
return $this->getAdapter()->execute($sql);
}
/**
* {@inheritdoc}
*/
public function query($sql)
{
return $this->getAdapter()->query($sql);
}
/**
* {@inheritdoc}
*/
public function fetchRow($sql)
{
return $this->getAdapter()->fetchRow($sql);
}
/**
* {@inheritdoc}
*/
public function fetchAll($sql)
{
return $this->getAdapter()->fetchAll($sql);
}
/**
* {@inheritdoc}
*/
public function insert($table, $data)
{
// convert to table object
if (is_string($table)) {
$table = new Table($table, [], $this->getAdapter());
}
$table->insert($data)->save();
}
/**
* {@inheritdoc}
*/
public function hasTable($tableName)
{
return $this->getAdapter()->hasTable($tableName);
}
/**
* {@inheritdoc}
*/
public function table($tableName, $options = [])
{
return new Table($tableName, $options, $this->getAdapter());
}
}
phinx-0.9.2/src/Phinx/Seed/Seed.template.php.dist 0000664 0000000 0000000 00000000533 13217376123 0021560 0 ustar 00root root 0000000 0000000
*/
interface SeedInterface
{
/**
* @var string
*/
const RUN = 'run';
/**
* Run the seeder.
*
* @return void
*/
public function run();
/**
* Sets the database adapter.
*
* @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
* @return \Phinx\Seed\SeedInterface
*/
public function setAdapter(AdapterInterface $adapter);
/**
* Gets the database adapter.
*
* @return \Phinx\Db\Adapter\AdapterInterface
*/
public function getAdapter();
/**
* Sets the input object to be used in migration object
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @return \Phinx\Seed\SeedInterface
*/
public function setInput(InputInterface $input);
/**
* Gets the input object to be used in migration object
*
* @return \Symfony\Component\Console\Input\InputInterface
*/
public function getInput();
/**
* Sets the output object to be used in migration object
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return \Phinx\Seed\SeedInterface
*/
public function setOutput(OutputInterface $output);
/**
* Gets the output object to be used in migration object
*
* @return \Symfony\Component\Console\Output\OutputInterface
*/
public function getOutput();
/**
* Gets the name.
*
* @return string
*/
public function getName();
/**
* Executes a SQL statement and returns the number of affected rows.
*
* @param string $sql SQL
* @return int
*/
public function execute($sql);
/**
* Executes a SQL statement and returns the result as an array.
*
* @param string $sql SQL
* @return array
*/
public function query($sql);
/**
* Executes a query and returns only one row as an array.
*
* @param string $sql SQL
* @return array
*/
public function fetchRow($sql);
/**
* Executes a query and returns an array of rows.
*
* @param string $sql SQL
* @return array
*/
public function fetchAll($sql);
/**
* Insert data into a table.
*
* @param string $tableName
* @param array $data
* @return void
*/
public function insert($tableName, $data);
/**
* Checks to see if a table exists.
*
* @param string $tableName Table Name
* @return bool
*/
public function hasTable($tableName);
/**
* Returns an instance of the \Table
class.
*
* You can use this class to create and manipulate tables.
*
* @param string $tableName Table Name
* @param array $options Options
* @return \Phinx\Db\Table
*/
public function table($tableName, $options);
}
phinx-0.9.2/src/Phinx/Util/ 0000775 0000000 0000000 00000000000 13217376123 0015447 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Util/Util.php 0000664 0000000 0000000 00000014314 13217376123 0017100 0 ustar 00root root 0000000 0000000 format(static::DATE_FORMAT);
}
/**
* Gets an array of all the existing migration class names.
*
* @return string[]
*/
public static function getExistingMigrationClassNames($path)
{
$classNames = [];
if (!is_dir($path)) {
return $classNames;
}
// filter the files to only get the ones that match our naming scheme
$phpFiles = glob($path . DIRECTORY_SEPARATOR . '*.php');
foreach ($phpFiles as $filePath) {
if (preg_match('/([0-9]+)_([_a-z0-9]*).php/', basename($filePath))) {
$classNames[] = static::mapFileNameToClassName(basename($filePath));
}
}
return $classNames;
}
/**
* Get the version from the beginning of a file name.
*
* @param string $fileName File Name
* @return string
*/
public static function getVersionFromFileName($fileName)
{
$matches = [];
preg_match('/^[0-9]+/', basename($fileName), $matches);
return $matches[0];
}
/**
* Turn migration names like 'CreateUserTable' into file names like
* '12345678901234_create_user_table.php' or 'LimitResourceNamesTo30Chars' into
* '12345678901234_limit_resource_names_to_30_chars.php'.
*
* @param string $className Class Name
* @return string
*/
public static function mapClassNameToFileName($className)
{
$arr = preg_split('/(?=[A-Z])/', $className);
unset($arr[0]); // remove the first element ('')
$fileName = static::getCurrentTimestamp() . '_' . strtolower(implode($arr, '_')) . '.php';
return $fileName;
}
/**
* Turn file names like '12345678901234_create_user_table.php' into class
* names like 'CreateUserTable'.
*
* @param string $fileName File Name
* @return string
*/
public static function mapFileNameToClassName($fileName)
{
$matches = [];
if (preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches)) {
$fileName = $matches[1];
}
return str_replace(' ', '', ucwords(str_replace('_', ' ', $fileName)));
}
/**
* Check if a migration class name is unique regardless of the
* timestamp.
*
* This method takes a class name and a path to a migrations directory.
*
* Migration class names must be in CamelCase format.
* e.g: CreateUserTable or AddIndexToPostsTable.
*
* Single words are not allowed on their own.
*
* @param string $className Class Name
* @param string $path Path
* @return bool
*/
public static function isUniqueMigrationClassName($className, $path)
{
$existingClassNames = static::getExistingMigrationClassNames($path);
return !(in_array($className, $existingClassNames));
}
/**
* Check if a migration/seed class name is valid.
*
* Migration & Seed class names must be in CamelCase format.
* e.g: CreateUserTable, AddIndexToPostsTable or UserSeeder.
*
* Single words are not allowed on their own.
*
* @param string $className Class Name
* @return bool
*/
public static function isValidPhinxClassName($className)
{
return (bool)preg_match('/^([A-Z][a-z0-9]+)+$/', $className);
}
/**
* Check if a migration file name is valid.
*
* @param string $fileName File Name
* @return bool
*/
public static function isValidMigrationFileName($fileName)
{
$matches = [];
return preg_match(static::MIGRATION_FILE_NAME_PATTERN, $fileName, $matches);
}
/**
* Check if a seed file name is valid.
*
* @param string $fileName File Name
* @return bool
*/
public static function isValidSeedFileName($fileName)
{
$matches = [];
return preg_match(static::SEED_FILE_NAME_PATTERN, $fileName, $matches);
}
/**
* Expands a set of paths with curly braces (if supported by the OS).
*
* @param array $paths
* @return array
*/
public static function globAll(array $paths)
{
$result = [];
foreach ($paths as $path) {
$result = array_merge($result, static::glob($path));
}
return $result;
}
/**
* Expands a path with curly braces (if supported by the OS).
*
* @param string $path
* @return array
*/
public static function glob($path)
{
return glob($path, defined('GLOB_BRACE') ? GLOB_BRACE : 0);
}
}
phinx-0.9.2/src/Phinx/Wrapper/ 0000775 0000000 0000000 00000000000 13217376123 0016152 5 ustar 00root root 0000000 0000000 phinx-0.9.2/src/Phinx/Wrapper/TextWrapper.php 0000664 0000000 0000000 00000016442 13217376123 0021157 0 ustar 00root root 0000000 0000000
*/
class TextWrapper
{
/**
* @var \Phinx\Console\PhinxApplication
*/
private $app;
/**
* @var array
*/
private $options = [];
/**
* @var integer
*/
private $exit_code;
/**
* @param \Phinx\Console\PhinxApplication $app
* @param array $options
*/
public function __construct(PhinxApplication $app, array $options = [])
{
$this->app = $app;
$this->options = $options;
}
/**
* Get the application instance.
*
* @return \Phinx\Console\PhinxApplication
*/
public function getApp()
{
return $this->app;
}
/**
* Returns the exit code from the last run command.
* @return int
*/
public function getExitCode()
{
return $this->exit_code;
}
/**
* Returns the output from running the "status" command.
* @param string $env environment name (optional)
* @return string
*/
public function getStatus($env = null)
{
$command = ['status'];
if ($env ?: $this->hasOption('environment')) {
$command += ['-e' => $env ?: $this->getOption('environment')];
}
if ($this->hasOption('configuration')) {
$command += ['-c' => $this->getOption('configuration')];
}
if ($this->hasOption('parser')) {
$command += ['-p' => $this->getOption('parser')];
}
return $this->executeRun($command);
}
/**
* Returns the output from running the "migrate" command.
* @param string $env environment name (optional)
* @param string $target target version (optional)
* @return string
*/
public function getMigrate($env = null, $target = null)
{
$command = ['migrate'];
if ($env ?: $this->hasOption('environment')) {
$command += ['-e' => $env ?: $this->getOption('environment')];
}
if ($this->hasOption('configuration')) {
$command += ['-c' => $this->getOption('configuration')];
}
if ($this->hasOption('parser')) {
$command += ['-p' => $this->getOption('parser')];
}
if ($target) {
$command += ['-t' => $target];
}
return $this->executeRun($command);
}
/**
* Returns the output from running the "seed:run" command.
* @param string|null $env environment name
* @param string|null $target target version
* @param array|string|null $seed array of seed names or seed name
* @return string
*/
public function getSeed($env = null, $target = null, $seed = null)
{
$command = ['seed:run'];
if ($env ?: $this->hasOption('environment')) {
$command += ['-e' => $env ?: $this->getOption('environment')];
}
if ($this->hasOption('configuration')) {
$command += ['-c' => $this->getOption('configuration')];
}
if ($this->hasOption('parser')) {
$command += ['-p' => $this->getOption('parser')];
}
if ($target) {
$command += ['-t' => $target];
}
if ($seed) {
$seed = (array)$seed;
$command += ['-s' => $seed];
}
return $this->executeRun($command);
}
/**
* Returns the output from running the "rollback" command.
* @param string $env environment name (optional)
* @param mixed $target target version, or 0 (zero) fully revert (optional)
* @return string
*/
public function getRollback($env = null, $target = null)
{
$command = ['rollback'];
if ($env ?: $this->hasOption('environment')) {
$command += ['-e' => $env ?: $this->getOption('environment')];
}
if ($this->hasOption('configuration')) {
$command += ['-c' => $this->getOption('configuration')];
}
if ($this->hasOption('parser')) {
$command += ['-p' => $this->getOption('parser')];
}
if (isset($target)) {
// Need to use isset() with rollback, because -t0 is a valid option!
// See http://docs.phinx.org/en/latest/commands.html#the-rollback-command
$command += ['-t' => $target];
}
return $this->executeRun($command);
}
/**
* Check option from options array
*
* @param string $key
* @return bool
*/
protected function hasOption($key)
{
return isset($this->options[$key]);
}
/**
* Get option from options array
*
* @param string $key
* @return string|null
*/
protected function getOption($key)
{
if (!isset($this->options[$key])) {
return null;
}
return $this->options[$key];
}
/**
* Set option in options array
*
* @param string $key
* @param string $value
* @return object
*/
public function setOption($key, $value)
{
$this->options[$key] = $value;
return $this;
}
/**
* Execute a command, capturing output and storing the exit code.
*
* @param array $command
* @return string
*/
protected function executeRun(array $command)
{
// Output will be written to a temporary stream, so that it can be
// collected after running the command.
$stream = fopen('php://temp', 'w+');
// Execute the command, capturing the output in the temporary stream
// and storing the exit code for debugging purposes.
$this->exit_code = $this->app->doRun(new ArrayInput($command), new StreamOutput($stream));
// Get the output of the command and close the stream, which will
// destroy the temporary file.
$result = stream_get_contents($stream, -1, 0);
fclose($stream);
return $result;
}
}
phinx-0.9.2/src/composer_autoloader.php 0000664 0000000 0000000 00000003115 13217376123 0020223 0 ustar 00root root 0000000 0000000