Initial commit: apps.supersam24.ru
This commit is contained in:
commit
e955e1da36
6566 files changed
+1271095
No files matched your search
Vendored
+9
@@ -0,0 +1,9 @@
|
||||
(The MIT license)
|
||||
|
||||
Copyright (c) 2012-present 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.
|
||||
Vendored
+135
@@ -0,0 +1,135 @@
|
||||
# [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 [book.cakephp.org/phinx](https://book.cakephp.org/phinx) ([EN](https://book.cakephp.org/phinx), [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 (https://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 http://docs.phinx.org/en/latest/ 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 [release notes](https://github.com/cakephp/phinx/releases).
|
||||
|
||||
### 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.
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
# 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.
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
# 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.
|
||||
Vendored
+36
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
/* Phinx
|
||||
*
|
||||
* (The MIT license)
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
|
||||
$autoloader = require __DIR__ . '/../src/composer_autoloader.php';
|
||||
|
||||
if (!$autoloader()) {
|
||||
die(
|
||||
'You need to set up the project dependencies using the following commands:' . PHP_EOL .
|
||||
'curl -sS https://getcomposer.org/installer | php' . PHP_EOL .
|
||||
'php composer.phar install' . PHP_EOL
|
||||
);
|
||||
}
|
||||
|
||||
return new Phinx\Console\PhinxApplication();
|
||||
Vendored
+83
@@ -0,0 +1,83 @@
|
||||
<?php
|
||||
/* Phinx
|
||||
*
|
||||
* (The MIT license)
|
||||
* Copyright (c) 2014 Rob Morgan
|
||||
* Copyright (c) 2014 Woody Gilk
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
// This script can be run as a router with the built in PHP web server:
|
||||
//
|
||||
// php -S localhost:8000 app/web.php
|
||||
//
|
||||
// Or can be run from any other web server with:
|
||||
//
|
||||
// require 'phinx/app/web.php';
|
||||
//
|
||||
// This script uses the following query string arguments:
|
||||
//
|
||||
// - (string) "e" environment name
|
||||
// - (string) "t" target version
|
||||
// - (boolean) "debug" enable debugging?
|
||||
|
||||
// Get the phinx console application and inject it into TextWrapper.
|
||||
$app = require __DIR__ . '/phinx.php';
|
||||
$wrap = new Phinx\Wrapper\TextWrapper($app);
|
||||
|
||||
// Mapping of route names to commands.
|
||||
$routes = [
|
||||
'status' => '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;
|
||||
Vendored
+28
@@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env php
|
||||
<?php
|
||||
/* Phinx
|
||||
*
|
||||
* (The MIT license)
|
||||
* Copyright (c) 2014 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.
|
||||
*/
|
||||
|
||||
$app = require __DIR__ . '/../app/phinx.php';
|
||||
$app->run();
|
||||
Vendored
+41
@@ -0,0 +1,41 @@
|
||||
@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
|
||||
Vendored
+60
@@ -0,0 +1,60 @@
|
||||
{
|
||||
"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",
|
||||
"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": "https://shadowhand.me",
|
||||
"role": "Developer"
|
||||
}, {
|
||||
"name": "Richard Quadling",
|
||||
"email": "rquadling@gmail.com",
|
||||
"role": "Developer"
|
||||
}, {
|
||||
"name": "CakePHP Community",
|
||||
"role": "Developer",
|
||||
"homepage": "https://github.com/cakephp/phinx/graphs/contributors"
|
||||
}],
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"cakephp/collection": "^3.7",
|
||||
"cakephp/database": "^3.7",
|
||||
"symfony/console": "^3.4|^4.0|^5.0",
|
||||
"symfony/config": "^3.4|^4.0|^5.0",
|
||||
"symfony/yaml": "^3.4|^4.0|^5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": ">=5.7,<8.0",
|
||||
"sebastian/comparator": ">=1.2.3",
|
||||
"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 --ignore=/tests/Phinx/Config/_rootDirectories/,/tests/log/ src/ tests/ app/",
|
||||
"cs-fix": "phpcbf --colors -p --standard=vendor/cakephp/cakephp-codesniffer/CakePHP --ignore=/tests/Phinx/Config/_rootDirectories/,/tests/log/ src/ tests/ app/",
|
||||
"test": "phpunit --colors=always"
|
||||
},
|
||||
"bin": ["bin/phinx"]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
# Generate the HTML output.
|
||||
FROM markstory/cakephp-docs-builder as builder
|
||||
|
||||
COPY docs /data/docs
|
||||
|
||||
# Build docs with sphinx
|
||||
RUN cd /data/docs-builder && \
|
||||
make website LANGS="en es fr ja" SOURCE=/data/docs DEST=/data/website
|
||||
|
||||
|
||||
# Build a small nginx container with just the static site in it.
|
||||
FROM nginx:1.15-alpine
|
||||
|
||||
COPY --from=builder /data/website /data/website
|
||||
COPY --from=builder /data/docs-builder/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Move files into final location
|
||||
RUN cp -R /data/website/html/* /usr/share/nginx/html \
|
||||
&& rm -rf /data/website/
|
||||
Whitespace-only changes.
+43
@@ -0,0 +1,43 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Phinx documentation build configuration file, created by
|
||||
# sphinx-quickstart on Thu Jun 14 17:39:42 2012.
|
||||
#
|
||||
|
||||
# Import the base theme configuration
|
||||
from cakephpsphinx.config.all import *
|
||||
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '0.11.x'
|
||||
|
||||
# The search index version.
|
||||
search_version = 'phinx-0'
|
||||
|
||||
# The marketing display name for the book.
|
||||
version_name = ''
|
||||
|
||||
# Project name shown in the black header bar
|
||||
project = 'Phinx'
|
||||
|
||||
# Other versions that display in the version picker menu.
|
||||
version_list = [
|
||||
{'name': '0.11', 'number': '/phinx/11', 'title': '0.11', 'current': True},
|
||||
]
|
||||
|
||||
# Languages available.
|
||||
languages = ['en', 'es', 'fr', 'ja']
|
||||
|
||||
# The GitHub branch name for this version of the docs
|
||||
# for edit links to point at.
|
||||
branch = 'master'
|
||||
|
||||
# Current version being built
|
||||
version = '0.11'
|
||||
|
||||
show_root_link = True
|
||||
|
||||
repository = 'cakephp/phinx'
|
||||
|
||||
source_path = 'docs/'
|
||||
|
||||
hide_page_contents = ('search', '404', 'contents')
|
||||
+401
@@ -0,0 +1,401 @@
|
||||
.. index::
|
||||
single: Commands
|
||||
|
||||
Commands
|
||||
========
|
||||
|
||||
Phinx is run using a number of commands.
|
||||
|
||||
The Breakpoint Command
|
||||
----------------------
|
||||
|
||||
The Breakpoint command is used to set breakpoints, allowing you to limit
|
||||
rollbacks. You can toggle the breakpoint of the most recent migration by
|
||||
not supplying any parameters.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development
|
||||
|
||||
To toggle a breakpoint on a specific version then use the ``--target``
|
||||
parameter or ``-t`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -t 20120103083322
|
||||
|
||||
You can remove all the breakpoints by using the ``--remove-all`` parameter
|
||||
or ``-r`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -r
|
||||
|
||||
You can set or unset (rather than just toggle) the breakpoint on the most
|
||||
recent migration (or on a specific migration when combined with the
|
||||
``--target`` or ``-t`` parameter) by using ``-set`` or ``--unset``.
|
||||
|
||||
Breakpoints are visible when you run the ``status`` command.
|
||||
|
||||
The Create Command
|
||||
------------------
|
||||
|
||||
The Create command is used to create a new migration file. It requires one
|
||||
argument: the name of the migration. The migration name should be specified in
|
||||
CamelCase format.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration
|
||||
|
||||
Open the new migration file in your text editor to add your database
|
||||
transformations. Phinx creates migration files using the path specified in your
|
||||
``phinx.yml`` file. Please see the :doc:`Configuration <configuration>` chapter
|
||||
for more information.
|
||||
|
||||
You are able to override the template file used by Phinx by supplying an
|
||||
alternative template filename.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --template="<file>"
|
||||
|
||||
You can also supply a template generating class. This class must implement the
|
||||
interface ``Phinx\Migration\CreationInterface``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --class="<class>"
|
||||
|
||||
In addition to providing the template for the migration, the class can also define
|
||||
a callback that will be called once the migration file has been generated from the
|
||||
template.
|
||||
|
||||
You cannot use ``--template`` and ``--class`` together.
|
||||
|
||||
The Init Command
|
||||
----------------
|
||||
|
||||
The Init command (short for initialize) is used to prepare your project for
|
||||
Phinx. This command generates the ``phinx.yml`` file in the root of your
|
||||
project directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init
|
||||
|
||||
Optionally you can specify a custom location for Phinx's config file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init ./custom/location/
|
||||
|
||||
You can also specify a custom file name:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init custom-config.yml
|
||||
|
||||
Open this file in your text editor to setup your project configuration. Please
|
||||
see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Migrate Command
|
||||
-------------------
|
||||
|
||||
The Migrate command runs all of the available migrations, optionally up to a
|
||||
specific version.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development
|
||||
|
||||
To migrate to a specific version then use the ``--target`` parameter or ``-t``
|
||||
for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development -t 20110103081132
|
||||
|
||||
Use ``--dry-run`` to print the queries to standard output without executing them
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate --dry-run
|
||||
|
||||
The Rollback Command
|
||||
--------------------
|
||||
|
||||
The Rollback command is used to undo previous migrations executed by Phinx. It
|
||||
is the opposite of the Migrate command.
|
||||
|
||||
You can rollback to the previous migration by using the ``rollback`` command
|
||||
with no arguments.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development
|
||||
|
||||
To rollback all migrations to a specific version then use the ``--target``
|
||||
parameter or ``-t`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 20120103083322
|
||||
|
||||
Specifying 0 as the target version will revert all migrations.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0
|
||||
|
||||
To rollback all migrations to a specific date then use the ``--date``
|
||||
parameter or ``-d`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -d 2012
|
||||
$ phinx rollback -e development -d 201201
|
||||
$ phinx rollback -e development -d 20120103
|
||||
$ phinx rollback -e development -d 2012010312
|
||||
$ phinx rollback -e development -d 201201031205
|
||||
$ phinx rollback -e development -d 20120103120530
|
||||
|
||||
If a breakpoint is set, blocking further rollbacks, you can override the
|
||||
breakpoint using the ``--force`` parameter or ``-f`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0 -f
|
||||
|
||||
Use ``--dry-run`` to print the queries to standard output without executing them
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback --dry-run
|
||||
|
||||
.. note::
|
||||
|
||||
When rolling back, Phinx orders the executed migrations using
|
||||
the order specified in the ``version_order`` option of your
|
||||
``phinx.yml`` file.
|
||||
Please see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Status Command
|
||||
------------------
|
||||
|
||||
The Status command prints a list of all migrations, along with their current
|
||||
status. You can use this command to determine which migrations have been run.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx status -e development
|
||||
|
||||
This command exits with code 0 if the database is up-to-date (ie. all migrations are up) or one of the following codes otherwise:
|
||||
|
||||
* 2: There is at least one missing migration.
|
||||
* 3: There is at least one down migration.
|
||||
|
||||
An exit code of 1 means an application error has occurred.
|
||||
|
||||
The Seed Create Command
|
||||
-----------------------
|
||||
|
||||
The Seed Create command can be used to create new database seed classes. It
|
||||
requires one argument, the name of the class. The class name should be specified
|
||||
in CamelCase format.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:create MyNewSeeder
|
||||
|
||||
Open the new seed file in your text editor to add your database seed commands.
|
||||
Phinx creates seed files using the path specified in your ``phinx.yml`` file.
|
||||
Please see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Seed Run Command
|
||||
--------------------
|
||||
|
||||
The Seed Run command runs all of the available seed classes or optionally just
|
||||
one.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development
|
||||
|
||||
To run only one seed class use the ``--seed`` parameter or ``-s`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development -s MyNewSeeder
|
||||
|
||||
Configuration File Parameter
|
||||
----------------------------
|
||||
|
||||
When running Phinx from the command line, you may specify a configuration file
|
||||
using the ``--configuration`` or ``-c`` parameter. In addition to YAML, the
|
||||
configuration file may be the computed output of a PHP file as a PHP array:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"adapter" => "mysql",
|
||||
"host" => $_ENV['DB_HOST'],
|
||||
"name" => $_ENV['DB_NAME'],
|
||||
"user" => $_ENV['DB_USER'],
|
||||
"pass" => $_ENV['DB_PASS'],
|
||||
"port" => $_ENV['DB_PORT']
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Phinx auto-detects which language parser to use for files with ``*.yml``, ``*.json``, and ``*.php`` extensions. The appropriate
|
||||
parser may also be specified via the ``--parser`` and ``-p`` parameters. Anything other than ``"json"`` or ``"php"`` is
|
||||
treated as YAML.
|
||||
|
||||
When using a PHP array, you can provide a ``connection`` key with an existing PDO instance. It is also important to pass
|
||||
the database name too, as Phinx requires this for certain methods such as ``hasTable()``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
),
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"name" => "dev_db",
|
||||
"connection" => $pdo_instance
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Running Phinx in a Web App
|
||||
--------------------------
|
||||
|
||||
Phinx can also be run inside of a web application by using the ``Phinx\Wrapper\TextWrapper``
|
||||
class. An example of this is provided in ``app/web.php``, which can be run as a
|
||||
standalone server:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php -S localhost:8000 vendor/robmorgan/phinx/app/web.php
|
||||
|
||||
This will create local web server at `<http://localhost:8000>`__ which will show current
|
||||
migration status by default. To run migrations up, use `<http://localhost:8000/migrate>`__
|
||||
and to rollback use `<http://localhost:8000/rollback>`__.
|
||||
|
||||
**The included web app is only an example and should not be used in production!**
|
||||
|
||||
.. note::
|
||||
|
||||
To modify configuration variables at runtime and override ``%%PHINX_DBNAME%%``
|
||||
or other another dynamic option, set ``$_SERVER['PHINX_DBNAME']`` before
|
||||
running commands. Available options are documented in the Configuration page.
|
||||
|
||||
Wrapping Phinx in another Symfony Console Application
|
||||
-----------------------------------------------------
|
||||
|
||||
Phinx can be wrapped and run as part of a separate Symfony console application. This
|
||||
may be desirable to present a unified interface to the user for all aspects of your
|
||||
application, or because you wish to run multiple Phinx commands. While you could
|
||||
run the commands through ``exec`` or use the above ``Phinx\Wrapper\TextWrapper``,
|
||||
though this makes it hard to deal with the return code and output in a similar fashion
|
||||
as your application.
|
||||
|
||||
Luckily, Symfony makes doing this sort of "meta" command straight-forward:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Symfony\Component\Console\Input\ArrayInput;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Phinx\Console\PhinxApplication;
|
||||
|
||||
// ...
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
|
||||
$phinx = new PhinxApplication();
|
||||
$command = $phinx->find('migrate');
|
||||
|
||||
$arguments = [
|
||||
'command' => 'migrate',
|
||||
'--environment' => 'production',
|
||||
'--configuration' => '/path/to/config/phinx.yml'
|
||||
];
|
||||
|
||||
$input = new ArrayInput($arguments);
|
||||
$returnCode = $command->run(new ArrayInput($arguments), $output);
|
||||
// ...
|
||||
}
|
||||
|
||||
Here, you are instantianting the ``PhinxApplication``, telling it to find the ``migrate``
|
||||
command, defining the arguments to pass to it (which match the commandline arguments and flags),
|
||||
and then finally running the command, passing it the same ``OutputInterface`` that your
|
||||
application uses.
|
||||
|
||||
See this `Symfony page <https://symfony.com/doc/current/console/calling_commands.html>`_ for more information.
|
||||
|
||||
Using Phinx with PHPUnit
|
||||
--------------------------
|
||||
|
||||
Phinx can be used within your unit tests to prepare or seed the database. You can use it programatically :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$app = new PhinxApplication();
|
||||
$app->setAutoExit(false);
|
||||
$app->run(new StringInput('migrate'), new NullOutput());
|
||||
}
|
||||
|
||||
If you use a memory database, you'll need to give Phinx a specific PDO instance. You can interact with Phinx directly
|
||||
using the Manager class :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use PDO;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Migration\Manager;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class DatabaseTestCase extends TestCase {
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$pdo = new PDO('sqlite::memory:', null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
]);
|
||||
$configArray = require('phinx.php');
|
||||
$configArray['environments']['test'] = [
|
||||
'adapter' => 'sqlite',
|
||||
'connection' => $pdo
|
||||
];
|
||||
$config = new Config($configArray);
|
||||
$manager = new Manager($config, new StringInput(' '), new NullOutput());
|
||||
$manager->migrate('test');
|
||||
$manager->seed('test');
|
||||
// You can change default fetch mode after the seeding
|
||||
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'en'
|
||||
+367
@@ -0,0 +1,367 @@
|
||||
.. index::
|
||||
single: Configuration
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
When you initialize your project using the :doc:`Init Command<commands>`, Phinx
|
||||
creates a default file in the root of your project directory. By default, this
|
||||
file uses the YAML data serialization format, but you can use the ``--format``
|
||||
command line option to specify either ``yml``, ``json``, or ``php``.
|
||||
|
||||
If a ``--configuration`` command line option is given, Phinx will load the
|
||||
specified file. Otherwise, it will attempt to find ``phinx.php``, ``phinx.json`` or
|
||||
``phinx.yml`` and load the first file found. See the :doc:`Commands <commands>`
|
||||
chapter for more information.
|
||||
|
||||
.. warning::
|
||||
|
||||
Remember to store the configuration file outside of a publicly accessible
|
||||
directory on your webserver. This file contains your database credentials
|
||||
and may be accidentally served as plain text.
|
||||
|
||||
Note that while JSON and YAML files are *parsed*, the PHP file is *included*.
|
||||
This means that:
|
||||
|
||||
* It must `return` an array of configuration items.
|
||||
* The variable scope is local, i.e. you would need to explicitly declare
|
||||
any global variables your initialization file reads or modifies.
|
||||
* Its standard output is suppressed.
|
||||
* Unlike with JSON and YAML, it is possible to omit environment connection details
|
||||
and instead specify ``connection`` which must contain an initialized PDO instance.
|
||||
This is useful when you want your migrations to interact with your application
|
||||
and/or share the same connection. However remember to also pass the database name
|
||||
as Phinx cannot infer this from the PDO connection.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$app = require 'app/phinx.php';
|
||||
$pdo = $app->getDatabase()->getPdo();
|
||||
|
||||
return [
|
||||
'environments' => [
|
||||
'default_database' => 'development',
|
||||
'development' => [
|
||||
'name' => 'devdb',
|
||||
'connection' => $pdo
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Migration Paths
|
||||
---------------
|
||||
|
||||
The first option specifies the path to your migration directory. Phinx uses
|
||||
``%%PHINX_CONFIG_DIR%%/db/migrations`` by default.
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` is a special token and is automatically replaced
|
||||
with the root directory where your ``phinx.yml`` file is stored.
|
||||
|
||||
In order to overwrite the default ``%%PHINX_CONFIG_DIR%%/db/migrations``, you
|
||||
need to add the following to the yaml configuration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: /your/full/path
|
||||
|
||||
You can also provide multiple migration paths by using an array in your configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations:
|
||||
- application/module1/migrations
|
||||
- application/module2/migrations
|
||||
|
||||
|
||||
You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
Migrations are captured with ``glob``, so you can define a pattern for multiple
|
||||
directories.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/module/*/{data,scripts}/migrations'
|
||||
|
||||
Custom Migration Base
|
||||
---------------------
|
||||
|
||||
By default all migrations will extend from Phinx's `AbstractMigration` class.
|
||||
This can be set to a custom class that extends from `AbstractMigration` by
|
||||
setting ``migration_base_class`` in your config:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
migration_base_class: MyMagicalMigration
|
||||
|
||||
Seed Paths
|
||||
----------
|
||||
|
||||
The second option specifies the path to your seed directory. Phinx uses
|
||||
``%%PHINX_CONFIG_DIR%%/db/seeds`` by default.
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` is a special token and is automatically replaced
|
||||
with the root directory where your ``phinx.yml`` file is stored.
|
||||
|
||||
In order to overwrite the default ``%%PHINX_CONFIG_DIR%%/db/seeds``, you
|
||||
need to add the following to the yaml configuration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: /your/full/path
|
||||
|
||||
You can also provide multiple seed paths by using an array in your configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds:
|
||||
- /your/full/path1
|
||||
- /your/full/path2
|
||||
|
||||
|
||||
You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
Environments
|
||||
------------
|
||||
|
||||
One of the key features of Phinx is support for multiple database environments.
|
||||
You can use Phinx to create migrations on your development environment, then
|
||||
run the same migrations on your production environment. Environments are
|
||||
specified under the ``environments`` nested collection. For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: localhost
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
port: 3306
|
||||
charset: utf8
|
||||
collation: utf8_unicode_ci
|
||||
|
||||
would define a new environment called ``production``.
|
||||
|
||||
In a situation when multiple developers work on the same project and each has
|
||||
a different environment (e.g. a convention such as ``<environment
|
||||
type>-<developer name>-<machine name>``), or when you need to have separate
|
||||
environments for separate purposes (branches, testing, etc) use environment
|
||||
variable `PHINX_ENVIRONMENT` to override the default environment in the yaml
|
||||
file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PHINX_ENVIRONMENT=dev-`whoami`-`hostname`
|
||||
|
||||
|
||||
Table Prefix and Suffix
|
||||
-----------------------
|
||||
|
||||
You can define a table prefix and table suffix:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
....
|
||||
table_prefix: dev_
|
||||
table_suffix: _v1
|
||||
testing:
|
||||
....
|
||||
table_prefix: test_
|
||||
table_suffix: _v2
|
||||
|
||||
|
||||
Socket Connections
|
||||
------------------
|
||||
|
||||
When using the MySQL adapter, it is also possible to use sockets instead of
|
||||
network connections. The socket path is configured with ``unix_socket``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
unix_socket: /var/run/mysql/mysql.sock
|
||||
charset: utf8
|
||||
|
||||
External Variables
|
||||
------------------
|
||||
|
||||
Phinx will automatically grab any environment variable prefixed with ``PHINX_``
|
||||
and make it available as a token in the config file. The token will have
|
||||
exactly the same name as the variable but you must access it by wrapping two
|
||||
``%%`` symbols on either side. e.g: ``'%%PHINX_DBUSER%%'``. This is especially
|
||||
useful if you wish to store your secret database credentials directly on the
|
||||
server and not in a version control system. This feature can be easily
|
||||
demonstrated by the following example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: '%%PHINX_DBHOST%%'
|
||||
name: '%%PHINX_DBNAME%%'
|
||||
user: '%%PHINX_DBUSER%%'
|
||||
pass: '%%PHINX_DBPASS%%'
|
||||
port: 3306
|
||||
charset: utf8
|
||||
|
||||
Data Source Names
|
||||
-----------------
|
||||
|
||||
Phinx supports the use of data source names (DSN) to specify the connection
|
||||
options, which can be useful if you use a single environment variable to hold
|
||||
the database credentials. PDO has a different DSN formats depending on the
|
||||
underlying driver, so Phinx uses a database-agnostic DSN format used by other
|
||||
projects (Doctrine, Rails, AMQP, PaaS, etc).
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
<adapter>://[<user>[:<pass>]@]<host>[:<port>]/<name>[?<additionalOptions>]
|
||||
|
||||
* A DSN requires at least ``adapter``, ``host`` and ``name``.
|
||||
* You cannot specify a password without a username.
|
||||
* ``port`` must be a positive integer.
|
||||
* ``additionalOptions`` takes the form of a query string, and will be passed to
|
||||
the adapter in the options array.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
# Example data source name
|
||||
dsn: mysql://root@localhost:3306/mydb?charset=utf8
|
||||
|
||||
Once a DSN is parsed, it's values are merged with the already existing
|
||||
connection options. Values in specified in a DSN will never override any value
|
||||
specified directly as connection options.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
development:
|
||||
dsn: %%DATABASE_URL%%
|
||||
production:
|
||||
dsn: %%DATABASE_URL%%
|
||||
name: production_database
|
||||
|
||||
If the supplied DSN is invalid, then it is completely ignored.
|
||||
|
||||
Supported Adapters
|
||||
------------------
|
||||
|
||||
Phinx currently supports the following database adapters natively:
|
||||
|
||||
* `MySQL <http://www.mysql.com/>`_: specify the ``mysql`` adapter.
|
||||
* `PostgreSQL <http://www.postgresql.org/>`_: specify the ``pgsql`` adapter.
|
||||
* `SQLite <http://www.sqlite.org/>`_: specify the ``sqlite`` adapter.
|
||||
* `SQL Server <http://www.microsoft.com/sqlserver>`_: specify the ``sqlsrv`` adapter.
|
||||
|
||||
SQLite
|
||||
`````````````````
|
||||
|
||||
Declaring an SQLite database uses a simplified structure:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
adapter: sqlite
|
||||
name: ./data/derby
|
||||
suffix: ".db" # Defaults to ".sqlite3"
|
||||
testing:
|
||||
adapter: sqlite
|
||||
memory: true # Setting memory to *any* value overrides name
|
||||
|
||||
SQL Server
|
||||
`````````````````
|
||||
|
||||
When using the ``sqlsrv`` adapter and connecting to a named instance you should
|
||||
omit the ``port`` setting as SQL Server will negotiate the port automatically.
|
||||
Additionally, omit the ``charset: utf8`` or change to ``charset: 65001`` which
|
||||
corresponds to UTF8 for SQL Server.
|
||||
|
||||
Custom Adapters
|
||||
`````````````````
|
||||
|
||||
You can provide a custom adapter by registering an implementation of the `Phinx\\Db\\Adapter\\AdapterInterface`
|
||||
with `AdapterFactory`:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$name = 'fizz';
|
||||
$class = 'Acme\Adapter\FizzAdapter';
|
||||
|
||||
AdapterFactory::instance()->registerAdapter($name, $class);
|
||||
|
||||
Adapters can be registered any time before `$app->run()` is called, which normally
|
||||
called by `bin/phinx`.
|
||||
|
||||
Aliases
|
||||
-------
|
||||
|
||||
Template creation class names can be aliased and used with the ``--class`` command line option for the :doc:`Create Command <commands>`.
|
||||
|
||||
The aliased classes will still be required to implement the ``Phinx\Migration\CreationInterface`` interface.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
aliases:
|
||||
permission: \Namespace\Migrations\PermissionMigrationTemplateGenerator
|
||||
view: \Namespace\Migrations\ViewMigrationTemplateGenerator
|
||||
|
||||
Version Order
|
||||
-------------
|
||||
|
||||
When rolling back or printing the status of migrations, Phinx orders the executed migrations according to the
|
||||
``version_order`` option, which can have the following values:
|
||||
|
||||
* ``creation`` (the default): migrations are ordered by their creation time, which is also part of their filename.
|
||||
* ``execution``: migrations are ordered by their execution time, also known as start time.
|
||||
|
||||
Bootstrap Path
|
||||
---------------
|
||||
|
||||
You can provide a path to a `bootstrap` php file that will included before any commands phinx commands are run. Note that
|
||||
setting External Variables to modify the config will not work because the config has already been parsed by this point.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
bootstrap: 'phinx-bootstrap.php'
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
Contents
|
||||
########
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Phinx
|
||||
|
||||
intro
|
||||
goals
|
||||
install
|
||||
migrations
|
||||
seeding
|
||||
commands
|
||||
configuration
|
||||
copyright
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
.. index::
|
||||
single: Copyright
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
License
|
||||
|
||||
(The MIT license)
|
||||
|
||||
Copyright (c) 2012 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.
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
.. index::
|
||||
single: Goals
|
||||
|
||||
Goals
|
||||
=====
|
||||
|
||||
Phinx was developed with the following goals in mind:
|
||||
|
||||
* Be portable amongst the most popular database vendors.
|
||||
* Be PHP framework independent.
|
||||
* Have a simple install process.
|
||||
* Have an easy to use command-line operation.
|
||||
* Integrate with various other PHP tools (Phing, PHPUnit) and web frameworks.
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
Phinx Documentation
|
||||
===================
|
||||
|
||||
Phinx makes it ridiculously easy to manage the database migrations for your PHP app. In less than 5 minutes, you can install Phinx using Composer and create your first database migration. Phinx is just about migrations without all the bloat of a database ORM system or application framework.
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
intro
|
||||
goals
|
||||
install
|
||||
migrations
|
||||
seeding
|
||||
commands
|
||||
configuration
|
||||
copyright
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`modindex`
|
||||
* :ref:`search`
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
.. index::
|
||||
single: Installation
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Phinx should be installed using Composer, which is a tool for dependency
|
||||
management in PHP. Please visit the `Composer <https://getcomposer.org/>`_
|
||||
website for more information.
|
||||
|
||||
.. note::
|
||||
|
||||
Phinx requires at least PHP 5.6 (or later).
|
||||
|
||||
To install Phinx, simply require it using Composer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php composer.phar require robmorgan/phinx
|
||||
|
||||
Create folders in your project following the structure ``db/migrations`` with adequate permissions.
|
||||
It is where your migration files will live and should be writable.
|
||||
|
||||
Phinx can now be executed from within your project:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
vendor/bin/phinx init
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
.. index::
|
||||
single: Introduction
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Good developers always version their code using a SCM system, so why don't they
|
||||
do the same for their database schema?
|
||||
|
||||
Phinx allows developers to alter and manipulate databases in a clear and
|
||||
concise way. It avoids the use of writing SQL by hand and instead offers a
|
||||
powerful API for creating migrations using PHP code. Developers can then
|
||||
version these migrations using their preferred SCM system. This makes Phinx
|
||||
migrations portable between different database systems. Phinx keeps track of
|
||||
which migrations have been run, so you can worry less about the state of your
|
||||
database and instead focus on building better software.
|
||||
+1802
File diff suppressed because it is too large.
Load diff
+152
@@ -0,0 +1,152 @@
|
||||
.. index::
|
||||
single: Supporting namespaces
|
||||
|
||||
PSR-4 compliance
|
||||
==================
|
||||
|
||||
Phinx allows the use of namespaces in Migrations and Seeders.
|
||||
Migrations require a timestamp in the filename, and therefore won't be fully PSR-4 compliant. Seeders do not need a timestamp and will be fully PSR-4 compliant.
|
||||
|
||||
Using namespaces
|
||||
------------------------
|
||||
1) locate your Phinx config file, the config file may be in one of following three formats: PHP, YAML or JSON.
|
||||
2) Locate the "paths" key inside the config file, it should look something like one of the below examples.
|
||||
- (NB. the "migrations" and "seeds" keys may be both an array or a string, so don't be alarmed if yours looks different)
|
||||
|
||||
PHP:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
'paths' => [
|
||||
'migrations' => 'database/migrations',
|
||||
'seeds' => 'database/seeds',
|
||||
],
|
||||
|
||||
|
||||
YAML:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: ./database/migrations
|
||||
seeds: ./database/seeds
|
||||
|
||||
JSON:
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"paths": {
|
||||
"migrations": "database/migrations",
|
||||
"seeds": "database/seeds"
|
||||
}
|
||||
}
|
||||
|
||||
3) Enabling namespaces is a fairly simple task, we're going to turn the "migrations" and "seeds" keys into arrays.
|
||||
- Any value without a key is a global-non-namespaced path
|
||||
- Any keyed value will use the key as namespace
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
'paths' => [
|
||||
'migrations' => [
|
||||
'/path/to/migration/without/namespace', // Non-namespaced migrations
|
||||
'Foo' => '/path/to/migration/Foo', // Migrations in the Foo namespace
|
||||
],
|
||||
'seeds' => [
|
||||
'/path/to/seeds/without/namespace', // Non-namespaced seeders
|
||||
'Baz' => '/path/to/seeds/Baz', // Seeders in the Baz namespace
|
||||
]
|
||||
],
|
||||
|
||||
PHP is a bit special in this case, as it allows keyless and keyed values in the same array. To make this configuration work in YAML and JSON, we have to key the non-namespaced path with "0".
|
||||
|
||||
.. code-block:: json
|
||||
|
||||
{
|
||||
"paths": {
|
||||
"migrations": {
|
||||
"0": "./db/migrations",
|
||||
"Foo\\Bar": "./src/FooBar/db/migrations"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations:
|
||||
0: ./db/migrations
|
||||
Foo\\Bar: ./src/FooBar/db/migrations
|
||||
|
||||
Path resolving
|
||||
^^^^^^^^^^^^^^
|
||||
|
||||
Let's take a closer look on how the paths are resolved, let's start with the non-namespaced path.
|
||||
|
||||
"./" refers to the project-root, therefore "./db/migrations" would resolve to <project-root>/db/migrations.
|
||||
This is the directory where Phinx will look for migrations when migrating.
|
||||
NB. these migrations must not have a namespace.
|
||||
|
||||
.. image:: http://i.imgur.com/l84308Q.jpg
|
||||
|
||||
This image shows the path for "./db/migrations" where "Phinx" is the project root.
|
||||
|
||||
And the namespaced path would be resolved as shown below.
|
||||
|
||||
"./src/FooBar/db/migrations" would resolve to <project-root>/src/FooBar/db/migrations, which is where Phinx will look for migrations in the Foo\\Bar namespace.
|
||||
|
||||
.. image:: http://i.imgur.com/2mg0V8V.jpg
|
||||
|
||||
The file path would look like this, if the project-root was "Phinx"
|
||||
|
||||
File examples
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
The non-namespaced file in <project-root>/db/migrations may look like the following example.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class CreateUserTable extends AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('users');
|
||||
$table->addColumn('name', 'string')->create();
|
||||
}
|
||||
}
|
||||
|
||||
Whereas the namespaced file will be found in <project-root>/src/FoorBar/db/migrations and can look like this:
|
||||
(Notice the namespace is the same as defined in the paths config).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
namespace Foo\Bar;
|
||||
|
||||
use Phinx\Migration\AbstractMigration;
|
||||
|
||||
class CreateUserTable extends AbstractMigration
|
||||
{
|
||||
public function change()
|
||||
{
|
||||
$table = $this->table('users');
|
||||
$table->addColumn('name', 'string')->create();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
4) That's it, you're ready to go, to create a migration simply run: *$ phinx create CreateUsersTable [--path ./src/FoorBar/db/migrations]*
|
||||
|
||||
- If multiple paths are configured, but none provided with the --path flag, you will be prompted for which path to use.
|
||||
|
||||
|
||||
Did you run into an issue?
|
||||
--------------------------
|
||||
|
||||
- Due to the way the migrations are created, it is impossible to generate a migration in the *global* namespace with a class-name that is the same as a migration in a user-defined namespace.
|
||||
+261
@@ -0,0 +1,261 @@
|
||||
.. index::
|
||||
single: Database Seeding
|
||||
|
||||
Database Seeding
|
||||
================
|
||||
|
||||
In version 0.5.0 Phinx introduced support for seeding your database with test
|
||||
data. Seed classes are a great way to easily fill your database with data after
|
||||
it's created. By default they are stored in the `seeds` directory; however, this
|
||||
path can be changed in your configuration file.
|
||||
|
||||
.. note::
|
||||
|
||||
Database seeding is entirely optional, and Phinx does not create a `seeds`
|
||||
directory by default.
|
||||
|
||||
Creating a New Seed Class
|
||||
-------------------------
|
||||
|
||||
Phinx includes a command to easily generate a new seed class:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:create UserSeeder
|
||||
|
||||
If you have specified multiple seed paths, you will be asked to select which
|
||||
path to create the new seed class in.
|
||||
|
||||
It is based on a skeleton template:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class MyNewSeeder extends AbstractSeed
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* http://docs.phinx.org/en/latest/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
The AbstractSeed Class
|
||||
----------------------
|
||||
|
||||
All Phinx seeds extend from the ``AbstractSeed`` class. This class provides the
|
||||
necessary support to create your seed classes. Seed classes are primarily used
|
||||
to insert test data.
|
||||
|
||||
The Run Method
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The run method is automatically invoked by Phinx when you execute the `seed:run`
|
||||
command. You should use this method to insert your test data.
|
||||
|
||||
.. note::
|
||||
|
||||
Unlike with migrations, Phinx does not keep track of which seed classes have
|
||||
been run. This means database seeders can be run repeatedly. Keep this in
|
||||
mind when developing them.
|
||||
|
||||
Foreign Key Dependencies
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Often you'll find that seeders need to run in a particular order, so they don't
|
||||
violate foreign key constraints. To define this order, you can implement the
|
||||
``getDependencies()`` method that returns an array of seeders to run before the
|
||||
current seeder:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class ShoppingCartSeeder extends AbstractSeed
|
||||
{
|
||||
public function getDependencies()
|
||||
{
|
||||
return [
|
||||
'UserSeeder',
|
||||
'ShopItemSeeder'
|
||||
];
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
// Seed the shopping cart after the `UserSeeder` and
|
||||
// `ShopItemSeeder` have been run.
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
Dependencies are only considered when executing all seed classes (default behavior).
|
||||
They won't be considered when running specific seed classes.
|
||||
|
||||
Inserting Data
|
||||
--------------
|
||||
|
||||
Using The Table Object
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Seed classes can also use the familiar `Table` object to insert data. You can
|
||||
retrieve an instance of the Table object by calling the ``table()`` method from
|
||||
within your seed class and then use the `insert()` method to insert data:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class PostsSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->saveData();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
You must call the `saveData()` method to commit your data to the table. Phinx
|
||||
will buffer data until you do so.
|
||||
|
||||
Integrating with the Faker library
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's trivial to use the awesome
|
||||
`Faker library <https://github.com/fzaninotto/Faker>`_ in your seed classes.
|
||||
Simply install it using Composer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer require fzaninotto/faker
|
||||
|
||||
Then use it in your seed classes:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$faker = Faker\Factory::create();
|
||||
$data = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$data[] = [
|
||||
'username' => $faker->userName,
|
||||
'password' => sha1($faker->password),
|
||||
'password_salt' => sha1('foo'),
|
||||
'email' => $faker->email,
|
||||
'first_name' => $faker->firstName,
|
||||
'last_name' => $faker->lastName,
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
}
|
||||
|
||||
$this->table('users')->insert($data)->saveData();
|
||||
}
|
||||
}
|
||||
|
||||
Truncating Tables
|
||||
-----------------
|
||||
|
||||
In addition to inserting data Phinx makes it trivial to empty your tables using the
|
||||
SQL `TRUNCATE` command:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->saveData();
|
||||
|
||||
// empty the table
|
||||
$posts->truncate();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
SQLite doesn't natively support the `TRUNCATE` command so behind the scenes
|
||||
`DELETE FROM` is used. It is recommended to call the `VACUUM` command
|
||||
after truncating a table. Phinx does not do this automatically.
|
||||
|
||||
Executing Seed Classes
|
||||
----------------------
|
||||
|
||||
This is the easy part. To seed your database, simply use the `seed:run` command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run
|
||||
|
||||
By default, Phinx will execute all available seed classes. If you would like to
|
||||
run a specific class, simply pass in the name of it using the `-s` parameter:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder
|
||||
|
||||
You can also run multiple seeders:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder -s PermissionSeeder -s LogSeeder
|
||||
|
||||
You can also use the `-v` parameter for more output verbosity:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -v
|
||||
|
||||
The Phinx seed functionality provides a simple mechanism to easily and repeatably
|
||||
insert test data into your database.
|
||||
+292
@@ -0,0 +1,292 @@
|
||||
. index::
|
||||
single: Commands
|
||||
|
||||
Comandos
|
||||
########
|
||||
|
||||
Phinx se corre usando un numero de comandos.
|
||||
|
||||
Migracion de Comandos
|
||||
=====================
|
||||
|
||||
Comando de Inicio
|
||||
|
||||
El comanado de inicio (manera corta de inicialización) se usa para preparar el proyecto Phinix. Este comando genera el archivo phinx.yml en el directorio raiz del proyecto:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init .
|
||||
|
||||
Abre este archivo en tu editor de texto para configurar tu projecto. Por favot mira el :doc:`Configuration <configuration>` para mas información.
|
||||
|
||||
Comando de creación.
|
||||
--------------------
|
||||
|
||||
El comando de creación se usa para crear un nuevo archivo de migración. Requiere un argumento: el nombre de la migración. El nombre de la migracion debera especificarse en el formato CamelCase:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration
|
||||
|
||||
Abre el nuevo archivo de migración en tu editor de texto para agregar las transformaciones de tu base de datos. Phinx crea archivos de migracion usando direcciones especificas en tu archivo phinx.yml . Por favor mire :doc:`Configuration <configuration>` para mas información.
|
||||
|
||||
Usted puede sobreescribir el archivo modelo usado por Phinx suministrando una alternativa del modelo de archivo:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --template="<file>"
|
||||
|
||||
Tambien puedes suministrar un modelo de clase general. Esta clase deberá implementar la interfaz ``Phinx\Migration\CreationInterface``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --class="<class>"
|
||||
|
||||
Además de proveer el modelo para la migracion, la clase tambien puede definir una "callback" que sera llamada una vez que el archivo de migración haya sido generado por el modelo.
|
||||
|
||||
No puede usar ``--template`` y ``--class`` juntos.
|
||||
|
||||
El comando de migración
|
||||
-----------------------
|
||||
|
||||
El comando de migración corre todas las migraciones que se encuentren disponibles, opcionalmente hasta una version especificada.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development
|
||||
|
||||
Para migrar a una version especifica se utiliza el parametro ``--targe`` o ``-t`` resumido.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development -t 20110103081132
|
||||
|
||||
Use ``--dry-run`` para imprimir las consultas a la salida sin ejecutarlas
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate --dry-run
|
||||
|
||||
|
||||
El comando para revertir
|
||||
------------------------
|
||||
|
||||
El comando para revertir se utiliza para deshacer las migraciones anteriores ejecutadas por Phinx. Es lo opuesto al comando Migrar.
|
||||
|
||||
Puede revertir a la migración anterior usando el comando rollback sin argumentos.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development
|
||||
|
||||
Para revertir todas las migraciones a una versión específica, use el parámetro ``--target`` o ``-t`` para abreviar
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 20120103083322
|
||||
|
||||
Especificar 0 como la versión de destino revertirá todas las migraciones.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0
|
||||
|
||||
Para revertir todas las migraciones a una fecha específica, use el parámetro ``--date`` o -d para abreviar.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -d 2012
|
||||
$ phinx rollback -e development -d 201201
|
||||
$ phinx rollback -e development -d 20120103
|
||||
$ phinx rollback -e development -d 2012010312
|
||||
$ phinx rollback -e development -d 201201031205
|
||||
$ phinx rollback -e development -d 20120103120530
|
||||
|
||||
Si se establece un punto de interrupción, bloqueando más reversiones, puede anular el punto de interrupción utilizando el parámetro ``--force`` o ``-f`` para abreviar
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0 -f
|
||||
|
||||
Utilice ``--dry-run`` para imprimir las consultas a la salida estándar sin ejecutarlas
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback --dry-run
|
||||
|
||||
.. note::
|
||||
|
||||
When rolling back, Phinx orders the executed migrations using the order specified in the version_order option of your phinx.yml file. Please see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
El comando de estado
|
||||
--------------------
|
||||
|
||||
El comando Estado imprime una lista de todas las migraciones, junto con su estado actual. Puede usar este comando para determinar qué migraciones se han ejecutado.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx status -e development
|
||||
|
||||
La salida de este comando es 0 si la base de datos está actualizada (es decir, todas las migraciones están activas) o uno de los siguientes códigos de lo contrario:
|
||||
|
||||
#. Queda por lo menos una migración por ejecutar.
|
||||
#: se ejecutó una migración y se registró en la base de datos, pero ahora falta
|
||||
el archivo de migración
|
||||
|
||||
El comando de interrupción
|
||||
---------------------------
|
||||
|
||||
El comando Punto de interrupción se usa para establecer puntos de interrupción, lo que le permite limitar los retrotracción. Puede alternar el punto de interrupción de la migración más reciente al no proporcionar ningún parámetro
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development
|
||||
|
||||
Para alternar un punto de interrupción en una versión específica, use el parámetro ``--target`` o ``-t`` para abreviar
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -t 20120103083322
|
||||
|
||||
Puede eliminar todos los puntos de interrupción utilizando el parámetro ``--remove-all`` o ``-r`` para abreviar.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -r
|
||||
|
||||
Los puntos de interrupción son visibles cuando ejecuta el comando de estado.
|
||||
|
||||
"Database Seeding"
|
||||
------------------
|
||||
|
||||
El comando Crear semilla se puede usar para crear nuevas clases de base de datos. Requiere un argumento, el nombre de la clase. El nombre de la clase debe especificarse en formato CamelCase.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:create MyNewSeeder
|
||||
|
||||
Abra el nuevo archivo semilla en su editor de texto para agregar los comandos semilla de su base de datos. Phinx crea archivos semilla utilizando la ruta especificada en su archivo phinx.yml. Consulte el capítulo: doc: `Configuration <configuración>` para obtener más información.
|
||||
|
||||
El comando de ejecución de semillas
|
||||
-----------------------------------
|
||||
|
||||
El comando Seed Run ejecuta todas las clases semilla disponibles u opcionalmente solo una.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development
|
||||
|
||||
Para ejecutar solo una clase semilla, use el parámetro ``--seed`` o ``-s`` para abreviar.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development -s MyNewSeeder
|
||||
|
||||
|
||||
Parámetro del archivo de configuración
|
||||
--------------------------------------
|
||||
|
||||
Al ejecutar Phinx desde la línea de comandos, puede especificar un archivo de configuración usando el parámetro ``--configuration`` o ``-c``. Además de YAML, el archivo de configuración puede ser la salida calculada de un archivo PHP como una matriz de PHP::
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"adapter" => "mysql",
|
||||
"host" => $_ENV['DB_HOST'],
|
||||
"name" => $_ENV['DB_NAME'],
|
||||
"user" => $_ENV['DB_USER'],
|
||||
"pass" => $_ENV['DB_PASS'],
|
||||
"port" => $_ENV['DB_PORT'],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Phinx detecta automáticamente qué analizador de idioma usar para los archivos con las extensiones ``.yml`` y ``.php``. El analizador apropiado también se puede especificar a través de los parámetros ``--parser`` y ``-p``. Cualquier otra cosa que no sea "php" se trata como YAML.
|
||||
|
||||
Al usar una matriz de PHP, puede proporcionar una clave de conexión con una instancia de PDO existente. También es importante pasar el nombre de la base de datos, ya que Phinx lo requiere para ciertos métodos como ``hasTable()``::
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"name" => "dev_db",
|
||||
"connection" => $pdo_instance
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Ejecutando Phinx en una aplicación web
|
||||
--------------------------------------
|
||||
|
||||
Phinx también se puede ejecutar dentro de una aplicación web utilizando la clase ``Phinx\Wrapper\TextWrapper``. Un ejemplo de esto se proporciona en **app/web.php**, que se puede ejecutar como un servidor independiente:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php -S localhost:8000 vendor/robmorgan/phinx/app/web.php
|
||||
|
||||
Esto creará un servidor web local en http://localhost:8000 que mostrará el estado actual de la migración de forma predeterminada. Para ejecutar las migraciones, use http://localhost:8000/migrate y para revertir use http: // localhost: 8000 / rollback.
|
||||
|
||||
La aplicación web incluida es solo un ejemplo y no debe utilizarse en producción
|
||||
|
||||
|
||||
.. note::
|
||||
Para modificar las variables de configuración en tiempo de ejecución
|
||||
e invalidar ``%%PHINX_DBNAME%%`` u otra opción dinámica, establezca ``$
|
||||
_SERVER['PHINX_DBNAME']`` antes de ejecutar los comandos. Las opciones
|
||||
disponibles están documentadas en la página de Configuración.
|
||||
|
||||
Usando Phinx con PHPUnit
|
||||
------------------------
|
||||
|
||||
Phinx puede usarse dentro de las pruebas de su unidad para preparar o sembrar la base de datos. Puedes usarlo programáticamente::
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$app = new PhinxApplication();
|
||||
$app->setAutoExit(false);
|
||||
$app->run(new StringInput('migrate'), new NullOutput());
|
||||
}
|
||||
|
||||
Si usa una base de datos de memoria, deberá darle a Phinx una instancia de PDO específica. Puedes interactuar con Phinx directamente usando la clase Manager::
|
||||
|
||||
use PDO;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Migration\Manager;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class DatabaseTestCase extends TestCase {
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$pdo = new PDO('sqlite::memory:', null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
]);
|
||||
$configArray = require('phinx.php');
|
||||
$configArray['environments']['test'] = [
|
||||
'adapter' => 'sqlite',
|
||||
'connection' => $pdo
|
||||
];
|
||||
$config = new Config($configArray);
|
||||
$manager = new Manager($config, new StringInput(' '), new NullOutput());
|
||||
$manager->migrate('test');
|
||||
$manager->seed('test');
|
||||
// You can change default fetch mode after the seeding
|
||||
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'es'
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
Contents
|
||||
########
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Phinx
|
||||
|
||||
commands
|
||||
+339
@@ -0,0 +1,339 @@
|
||||
.. index::
|
||||
single: Commands
|
||||
|
||||
Commands
|
||||
########
|
||||
|
||||
Phinx is run using a number of commands.
|
||||
|
||||
Migration Commands
|
||||
==================
|
||||
|
||||
The Init Command
|
||||
|
||||
The Init command (short for initialize) is used to prepare your project for
|
||||
Phinx. This command generates the ``phinx.yml`` file in the root of your
|
||||
project directory.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init .
|
||||
|
||||
Open this file in your text editor to setup your project configuration. Please
|
||||
see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Create Command
|
||||
------------------
|
||||
|
||||
The Create command is used to create a new migration file. It requires one
|
||||
argument: the name of the migration. The migration name should be specified in
|
||||
CamelCase format.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration
|
||||
|
||||
Open the new migration file in your text editor to add your database
|
||||
transformations. Phinx creates migration files using the path specified in your
|
||||
``phinx.yml`` file. Please see the :doc:`Configuration <configuration>` chapter
|
||||
for more information.
|
||||
|
||||
You are able to override the template file used by Phinx by supplying an
|
||||
alternative template filename.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --template="<file>"
|
||||
|
||||
You can also supply a template generating class. This class must implement the
|
||||
interface ``Phinx\Migration\CreationInterface``.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --class="<class>"
|
||||
|
||||
In addition to providing the template for the migration, the class can also define
|
||||
a callback that will be called once the migration file has been generated from the
|
||||
template.
|
||||
|
||||
You cannot use ``--template`` and ``--class`` together.
|
||||
|
||||
The Migrate Command
|
||||
-------------------
|
||||
|
||||
The Migrate command runs all of the available migrations, optionally up to a
|
||||
specific version.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development
|
||||
|
||||
To migrate to a specific version then use the ``--target`` parameter or ``-t``
|
||||
for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development -t 20110103081132
|
||||
|
||||
Use ``--dry-run`` to print the queries to standard output without executing them
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate --dry-run
|
||||
|
||||
The Rollback Command
|
||||
--------------------
|
||||
|
||||
The Rollback command is used to undo previous migrations executed by Phinx. It
|
||||
is the opposite of the Migrate command.
|
||||
|
||||
You can rollback to the previous migration by using the ``rollback`` command
|
||||
with no arguments.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development
|
||||
|
||||
To rollback all migrations to a specific version then use the ``--target``
|
||||
parameter or ``-t`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 20120103083322
|
||||
|
||||
Specifying 0 as the target version will revert all migrations.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0
|
||||
|
||||
To rollback all migrations to a specific date then use the ``--date``
|
||||
parameter or ``-d`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -d 2012
|
||||
$ phinx rollback -e development -d 201201
|
||||
$ phinx rollback -e development -d 20120103
|
||||
$ phinx rollback -e development -d 2012010312
|
||||
$ phinx rollback -e development -d 201201031205
|
||||
$ phinx rollback -e development -d 20120103120530
|
||||
|
||||
If a breakpoint is set, blocking further rollbacks, you can override the
|
||||
breakpoint using the ``--force`` parameter or ``-f`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0 -f
|
||||
|
||||
Use ``--dry-run`` to print the queries to standard output without executing them
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback --dry-run
|
||||
|
||||
.. note::
|
||||
|
||||
When rolling back, Phinx orders the executed migrations using
|
||||
the order specified in the ``version_order`` option of your
|
||||
``phinx.yml`` file.
|
||||
Please see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Status Command
|
||||
------------------
|
||||
|
||||
The Status command prints a list of all migrations, along with their current
|
||||
status. You can use this command to determine which migrations have been run.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx status -e development
|
||||
|
||||
This command exits with code 0 if the database is up-to-date (ie. all migrations are up) or one of the following codes otherwise:
|
||||
|
||||
* 1: There is at least one migration left to be executed.
|
||||
* 2: There was a migration run and recorded in the database, but the migration file is now missing.
|
||||
|
||||
The Breakpoint Command
|
||||
----------------------
|
||||
|
||||
The Breakpoint command is used to set breakpoints, allowing you to limit
|
||||
rollbacks. You can toggle the breakpoint of the most recent migration by
|
||||
not supplying any parameters.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development
|
||||
|
||||
To toggle a breakpoint on a specific version then use the ``--target``
|
||||
parameter or ``-t`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -t 20120103083322
|
||||
|
||||
You can remove all the breakpoints by using the ``--remove-all`` parameter
|
||||
or ``-r`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -r
|
||||
|
||||
Breakpoints are visible when you run the ``status`` command.
|
||||
|
||||
Database Seeding
|
||||
================
|
||||
|
||||
The Seed Create Command
|
||||
-----------------------
|
||||
|
||||
The Seed Create command can be used to create new database seed classes. It
|
||||
requires one argument, the name of the class. The class name should be specified
|
||||
in CamelCase format.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:create MyNewSeeder
|
||||
|
||||
Open the new seed file in your text editor to add your database seed commands.
|
||||
Phinx creates seed files using the path specified in your ``phinx.yml`` file.
|
||||
Please see the :doc:`Configuration <configuration>` chapter for more information.
|
||||
|
||||
The Seed Run Command
|
||||
--------------------
|
||||
|
||||
The Seed Run command runs all of the available seed classes or optionally just
|
||||
one.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development
|
||||
|
||||
To run only one seed class use the ``--seed`` parameter or ``-s`` for short.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development -s MyNewSeeder
|
||||
|
||||
Configuration File Parameter
|
||||
----------------------------
|
||||
|
||||
When running Phinx from the command line, you may specify a configuration file
|
||||
using the ``--configuration`` or ``-c`` parameter. In addition to YAML, the
|
||||
configuration file may be the computed output of a PHP file as a PHP array:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"adapter" => "mysql",
|
||||
"host" => $_ENV['DB_HOST'],
|
||||
"name" => $_ENV['DB_NAME'],
|
||||
"user" => $_ENV['DB_USER'],
|
||||
"pass" => $_ENV['DB_PASS'],
|
||||
"port" => $_ENV['DB_PORT'],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Phinx auto-detects which language parser to use for files with ``*.yml`` and ``*.php`` extensions. The appropriate
|
||||
parser may also be specified via the ``--parser`` and ``-p`` parameters. Anything other than ``"php"`` is treated as YAML.
|
||||
|
||||
When using a PHP array, you can provide a ``connection`` key with an existing PDO instance. It is also important to pass
|
||||
the database name too, as Phinx requires this for certain methods such as ``hasTable()``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"name" => "dev_db",
|
||||
"connection" => $pdo_instance
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Running Phinx in a Web App
|
||||
--------------------------
|
||||
|
||||
Phinx can also be run inside of a web application by using the ``Phinx\Wrapper\TextWrapper``
|
||||
class. An example of this is provided in ``app/web.php``, which can be run as a
|
||||
standalone server:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php -S localhost:8000 vendor/robmorgan/phinx/app/web.php
|
||||
|
||||
This will create local web server at `<http://localhost:8000>`__ which will show current
|
||||
migration status by default. To run migrations up, use `<http://localhost:8000/migrate>`__
|
||||
and to rollback use `<http://localhost:8000/rollback>`__.
|
||||
|
||||
**The included web app is only an example and should not be used in production!**
|
||||
|
||||
.. note::
|
||||
|
||||
To modify configuration variables at runtime and override ``%%PHINX_DBNAME%%``
|
||||
or other another dynamic option, set ``$_SERVER['PHINX_DBNAME']`` before
|
||||
running commands. Available options are documented in the Configuration page.
|
||||
|
||||
Using Phinx with PHPUnit
|
||||
--------------------------
|
||||
|
||||
Phinx can be used within your unit tests to prepare or seed the database. You can use it programatically :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$app = new PhinxApplication();
|
||||
$app->setAutoExit(false);
|
||||
$app->run(new StringInput('migrate'), new NullOutput());
|
||||
}
|
||||
|
||||
If you use a memory database, you'll need to give Phinx a specific PDO instance. You can interact with Phinx directly using the Manager class :
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use PDO;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Migration\Manager;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class DatabaseTestCase extends TestCase {
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$pdo = new PDO('sqlite::memory:', null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
]);
|
||||
$configArray = require('phinx.php');
|
||||
$configArray['environments']['test'] = [
|
||||
'adapter' => 'sqlite',
|
||||
'connection' => $pdo
|
||||
];
|
||||
$config = new Config($configArray);
|
||||
$manager = new Manager($config, new StringInput(' '), new NullOutput());
|
||||
$manager->migrate('test');
|
||||
$manager->seed('test');
|
||||
// You can change default fetch mode after the seeding
|
||||
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'fr'
|
||||
+308
@@ -0,0 +1,308 @@
|
||||
.. index::
|
||||
single: Configuration
|
||||
|
||||
Configuration
|
||||
=============
|
||||
|
||||
When you initialize your project using the :doc:`Init Command<commands>`, Phinx
|
||||
creates a default file called ``phinx.yml`` in the root of your project directory.
|
||||
This file uses the YAML data serialization format.
|
||||
|
||||
If a ``--configuration`` command line option is given, Phinx will load the
|
||||
specified file. Otherwise, it will attempt to find ``phinx.php``, ``phinx.json`` or
|
||||
``phinx.yml`` and load the first file found. See the :doc:`Commands <commands>`
|
||||
chapter for more information.
|
||||
|
||||
.. warning::
|
||||
|
||||
Remember to store the configuration file outside of a publicly accessible
|
||||
directory on your webserver. This file contains your database credentials
|
||||
and may be accidentally served as plain text.
|
||||
|
||||
Note that while JSON and YAML files are *parsed*, the PHP file is *included*.
|
||||
This means that:
|
||||
|
||||
* It must `return` an array of configuration items.
|
||||
* The variable scope is local, i.e. you would need to explicitly declare
|
||||
any global variables your initialization file reads or modifies.
|
||||
* Its standard output is suppressed.
|
||||
* Unlike with JSON and YAML, it is possible to omit environment connection details
|
||||
and instead specify ``connection`` which must contain an initialized PDO instance.
|
||||
This is useful when you want your migrations to interact with your application
|
||||
and/or share the same connection. However remember to also pass the database name
|
||||
as Phinx cannot infer this from the PDO connection.
|
||||
|
||||
::
|
||||
|
||||
<?php
|
||||
require 'app/init.php';
|
||||
|
||||
global $app;
|
||||
$pdo = $app->getDatabase()->getPdo();
|
||||
|
||||
return ['environments' =>
|
||||
[
|
||||
'default_database' => 'development',
|
||||
'development' => [
|
||||
'name' => 'devdb',
|
||||
'connection' => $pdo,
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Migration Paths
|
||||
---------------
|
||||
|
||||
The first option specifies the path to your migration directory. Phinx uses
|
||||
``%%PHINX_CONFIG_DIR%%/db/migrations`` by default.
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` is a special token and is automatically replaced
|
||||
with the root directory where your ``phinx.yml`` file is stored.
|
||||
|
||||
In order to overwrite the default ``%%PHINX_CONFIG_DIR%%/db/migrations``, you
|
||||
need to add the following to the yaml configuration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: /your/full/path
|
||||
|
||||
You can also provide multiple migration paths by using an array in your configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations:
|
||||
- application/module1/migrations
|
||||
- application/module2/migrations
|
||||
|
||||
You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
Migrations are captured with ``glob``, so you can define a pattern for multiple
|
||||
directories.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/module/*/{data,scripts}/migrations'
|
||||
|
||||
Custom Migration Base
|
||||
---------------------
|
||||
|
||||
By default all migrations will extend from Phinx's ``AbstractMigration`` class.
|
||||
This can be set to a custom class that extends from ``AbstractMigration`` by
|
||||
setting ``migration_base_class`` in your config:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
migration_base_class: MyMagicalMigration
|
||||
|
||||
Seed Paths
|
||||
----------
|
||||
|
||||
The second option specifies the path to your seed directory. Phinx uses
|
||||
``%%PHINX_CONFIG_DIR%%/db/seeds`` by default.
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` is a special token and is automatically replaced
|
||||
with the root directory where your ``phinx.yml`` file is stored.
|
||||
|
||||
In order to overwrite the default ``%%PHINX_CONFIG_DIR%%/db/seeds``, you
|
||||
need to add the following to the yaml configuration.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: /your/full/path
|
||||
|
||||
You can also provide multiple seed paths by using an array in your configuration:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds:
|
||||
- /your/full/path1
|
||||
- /your/full/path2
|
||||
|
||||
You can also use the ``%%PHINX_CONFIG_DIR%%`` token in your path.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
Environments
|
||||
------------
|
||||
|
||||
One of the key features of Phinx is support for multiple database environments.
|
||||
You can use Phinx to create migrations on your development environment, then
|
||||
run the same migrations on your production environment. Environments are
|
||||
specified under the ``environments`` nested collection. For example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: localhost
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
port: 3306
|
||||
charset: utf8
|
||||
collation: utf8_unicode_ci
|
||||
|
||||
would define a new environment called ``production``.
|
||||
|
||||
In a situation when multiple developers work on the same project and each has
|
||||
a different environment (e.g. a convention such as ``<environment
|
||||
type>-<developer name>-<machine name>``), or when you need to have separate
|
||||
environments for separate purposes (branches, testing, etc) use environment
|
||||
variable `PHINX_ENVIRONMENT` to override the default environment in the yaml
|
||||
file:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PHINX_ENVIRONMENT=dev-`whoami`-`hostname`
|
||||
|
||||
Table Prefix and Suffix
|
||||
-----------------------
|
||||
|
||||
You can define a table prefix and table suffix:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
....
|
||||
table_prefix: dev_
|
||||
table_suffix: _v1
|
||||
testing:
|
||||
....
|
||||
table_prefix: test_
|
||||
table_suffix: _v2
|
||||
|
||||
Socket Connections
|
||||
------------------
|
||||
|
||||
When using the MySQL adapter, it is also possible to use sockets instead of
|
||||
network connections. The socket path is configured with ``unix_socket``:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
unix_socket: /var/run/mysql/mysql.sock
|
||||
charset: utf8
|
||||
|
||||
External Variables
|
||||
------------------
|
||||
|
||||
Phinx will automatically grab any environment variable prefixed with ``PHINX_``
|
||||
and make it available as a token in the config file. The token will have
|
||||
exactly the same name as the variable but you must access it by wrapping two
|
||||
``%%`` symbols on either side. e.g: ``%%PHINX_DBUSER%%``. This is especially
|
||||
useful if you wish to store your secret database credentials directly on the
|
||||
server and not in a version control system. This feature can be easily
|
||||
demonstrated by the following example:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: '%%PHINX_DBHOST%%'
|
||||
name: '%%PHINX_DBNAME%%'
|
||||
user: '%%PHINX_DBUSER%%'
|
||||
pass: '%%PHINX_DBPASS%%'
|
||||
port: 3306
|
||||
charset: utf8
|
||||
|
||||
Supported Adapters
|
||||
------------------
|
||||
|
||||
Phinx currently supports the following database adapters natively:
|
||||
|
||||
* `MySQL <http://www.mysql.com/>`_: specify the ``mysql`` adapter.
|
||||
* `PostgreSQL <http://www.postgresql.org/>`_: specify the ``pgsql`` adapter.
|
||||
* `SQLite <http://www.sqlite.org/>`_: specify the ``sqlite`` adapter.
|
||||
* `SQL Server <http://www.microsoft.com/sqlserver>`_: specify the ``sqlsrv`` adapter.
|
||||
|
||||
SQLite
|
||||
~~~~~~
|
||||
|
||||
Declaring an SQLite database uses a simplified structure:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
adapter: sqlite
|
||||
name: ./data/derby
|
||||
testing:
|
||||
adapter: sqlite
|
||||
memory: true # Setting memory to *any* value overrides name
|
||||
|
||||
SQL Server
|
||||
~~~~~~~~~~
|
||||
|
||||
When using the ``sqlsrv`` adapter and connecting to a named instance you should
|
||||
omit the ``port`` setting as SQL Server will negotiate the port automatically.
|
||||
Additionally, omit the ``charset: utf8`` or change to ``charset: 65001`` which
|
||||
corresponds to UTF8 for SQL Server.
|
||||
|
||||
Custom Adapters
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
You can provide a custom adapter by registering an implementation of the
|
||||
``Phinx\\Db\\Adapter\\AdapterInterface`` with ``AdapterFactory``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$name = 'fizz';
|
||||
$class = 'Acme\Adapter\FizzAdapter';
|
||||
|
||||
AdapterFactory::instance()->registerAdapter($name, $class);
|
||||
|
||||
Adapters can be registered any time before `$app->run()` is called, which normally
|
||||
called by `bin/phinx`.
|
||||
|
||||
Aliases
|
||||
-------
|
||||
|
||||
Template creation class names can be aliased and used with the ``--class`` command line option for the :doc:`Create Command <commands>`.
|
||||
|
||||
The aliased classes will still be required to implement the ``Phinx\Migration\CreationInterface`` interface.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
aliases:
|
||||
permission: \Namespace\Migrations\PermissionMigrationTemplateGenerator
|
||||
view: \Namespace\Migrations\ViewMigrationTemplateGenerator
|
||||
|
||||
Version Order
|
||||
-------------
|
||||
|
||||
When rolling back or printing the status of migrations, Phinx orders the executed migrations according to the
|
||||
``version_order`` option, which can have the following values:
|
||||
|
||||
* ``creation`` (the default): migrations are ordered by their creation time, which is also part of their filename.
|
||||
* ``execution``: migrations are ordered by their execution time, also known as start time.
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
Contenus
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
index
|
||||
migrations
|
||||
seeding
|
||||
commands
|
||||
configuration
|
||||
+57
@@ -0,0 +1,57 @@
|
||||
Phinx Migrations
|
||||
################
|
||||
|
||||
Phinx est un utilitaire autonome en ligne de commande pour gérer les Migrations de bases de données. Le plugin officiel de Migrations de CakePHP est basé sur cet outil.
|
||||
|
||||
Phinx rend ridiculement simple la gestion des migrations de bases de données pour vos applications PHP. En moins de 5 minutes,
|
||||
vous pouvez installer Composer et créer votre première migration de base de données. Phinx ne s'occupe que de la migration des
|
||||
bases de données, il laisse de côté les aspects ORM de la base de données et le cadre applicatif.
|
||||
|
||||
Introduction
|
||||
============
|
||||
|
||||
Les bons développeurs gèrent toujours leurs codes sources avec un outil de gestion de versions,
|
||||
alors pourquoi ne feraient-ils pas la même chose avec leurs schémas de bases de données.
|
||||
|
||||
Phinx permet aux développeurs de modifier et de manipuler leurs bases de données d'une façon claire et concise. Il évite
|
||||
d'avoir à écrire du SQL à la main et offre à la place une API puissante pour écrire des scripts de migration en utilisant PHP.
|
||||
Les développeurs peuvent alors versionner ces fichiers de migration en utilisant leur outil de versionnement préféré. Cela rend
|
||||
les migrations Phinx indépendantes des moteurs de base de données. Phinx conserve la trace des migrations précédentes, cela
|
||||
permet de se concentrer un peu plus sur l'amélioration de votre application et un peu moins sur l'état de votre base de
|
||||
données.
|
||||
|
||||
Objectifs
|
||||
=========
|
||||
|
||||
Phinx a été développé avec les objectifs suivants en tête :
|
||||
|
||||
* Être portable entre les principaux moteurs de base de données.
|
||||
* Être indépendant de tout framework PHP.
|
||||
* Être aisement installable.
|
||||
* Être utilisable facilement en ligne de commande.
|
||||
* Être intégrable avec d'autres outils PHP (Phing, PHPUnit) et des frameworks web.
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
Phinx devrait être installé en utilisant Composer, qui est un outil pour la gestion des dépendances en PHP. Visiter le site
|
||||
internet de `Composer <https://getcomposer.org/>`_ pour avoir plus d’informations.
|
||||
|
||||
.. note::
|
||||
|
||||
Phinx a besoin au minimum de PHP 5.4 (ou supérieur)
|
||||
|
||||
Pour installer Phinx, il suffit simplement de l'appeler via Composer
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php composer.phar require robmorgan/phinx
|
||||
|
||||
Créez les dossiers ``db/migrations`` dans votre projet en vous assurant que les droits sont bien configurés.
|
||||
C’est à cet endroit que vos fichiers de migrations devraient être créés et laissés.
|
||||
|
||||
Phinx peut maintenant être exécuté depuis la racine de votre projet.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
vendor/bin/phinx init
|
||||
+1305
File diff suppressed because it is too large.
Load diff
+217
@@ -0,0 +1,217 @@
|
||||
.. index::
|
||||
single: Database Seeding
|
||||
|
||||
Database Seeding
|
||||
================
|
||||
|
||||
In version 0.5.0 Phinx introduced support for seeding your database with test
|
||||
data. Seed classes are a great way to easily fill your database with data after
|
||||
it's created. By default they are stored in the ``seeds`` directory; however,
|
||||
this path can be changed in your configuration file.
|
||||
|
||||
.. note::
|
||||
|
||||
Database seeding is entirely optional, and Phinx does not create a ``seeds``
|
||||
directory by default.
|
||||
|
||||
Creating a New Seed Class
|
||||
-------------------------
|
||||
|
||||
Phinx includes a command to easily generate a new seed class:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:create UserSeeder
|
||||
|
||||
If you have specified multiple seed paths, you will be asked to select which
|
||||
path to create the new seed class in.
|
||||
|
||||
It is based on a skeleton template::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class MyNewSeeder extends AbstractSeed
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* http://docs.phinx.org/en/latest/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
The AbstractSeed Class
|
||||
----------------------
|
||||
|
||||
All Phinx seeds extend from the ``AbstractSeed`` class. This class provides the
|
||||
necessary support to create your seed classes. Seed classes are primarily used
|
||||
to insert test data.
|
||||
|
||||
The Run Method
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
The run method is automatically invoked by Phinx when you execute the `seed:run`
|
||||
command. You should use this method to insert your test data.
|
||||
|
||||
.. note::
|
||||
|
||||
Unlike with migrations, Phinx does not keep track of which seed classes have
|
||||
been run. This means database seeders can be run repeatedly. Keep this in
|
||||
mind when developing them.
|
||||
|
||||
Inserting Data
|
||||
--------------
|
||||
|
||||
Using The Table Object
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Seed classes can also use the familiar ``Table`` object to insert data. You can
|
||||
retrieve an instance of the Table object by calling the ``table()`` method from
|
||||
within your seed class and then use the ``insert()`` method to insert data::
|
||||
|
||||
<?php
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class PostsSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
You must call the ``save()`` method to commit your data to the table. Phinx
|
||||
will buffer data until you do so.
|
||||
|
||||
Integrating with the Faker library
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It's trivial to use the awesome
|
||||
`Faker library <https://github.com/fzaninotto/Faker>`_ in your seed classes.
|
||||
Simply install it using Composer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer require fzaninotto/faker
|
||||
|
||||
Then use it in your seed classes::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$faker = Faker\Factory::create();
|
||||
$data = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$data[] = [
|
||||
'username' => $faker->userName,
|
||||
'password' => sha1($faker->password),
|
||||
'password_salt' => sha1('foo'),
|
||||
'email' => $faker->email,
|
||||
'first_name' => $faker->firstName,
|
||||
'last_name' => $faker->lastName,
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
}
|
||||
|
||||
$this->insert('users', $data);
|
||||
}
|
||||
}
|
||||
|
||||
Truncating Tables
|
||||
-----------------
|
||||
|
||||
In addition to inserting data Phinx makes it trivial to empty your tables using
|
||||
the SQL ``TRUNCATE`` command::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->save();
|
||||
|
||||
// empty the table
|
||||
$posts->truncate();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
SQLite doesn't natively support the ``TRUNCATE`` command so behind the scenes
|
||||
``DELETE FROM`` is used. It is recommended to call the ``VACUUM`` command
|
||||
after truncating a table. Phinx does not do this automatically.
|
||||
|
||||
Executing Seed Classes
|
||||
----------------------
|
||||
|
||||
This is the easy part. To seed your database, simply use the ``seed:run`` command:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run
|
||||
|
||||
By default, Phinx will execute all available seed classes. If you would like to
|
||||
run a specific class, simply pass in the name of it using the ``-s`` parameter:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder
|
||||
|
||||
You can also run multiple seeders:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder -s PermissionSeeder -s LogSeeder
|
||||
|
||||
You can also use the ``-v`` parameter for more output verbosity:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -v
|
||||
|
||||
The Phinx seed functionality provides a simple mechanism to easily and repeatably
|
||||
insert test data into your database.
|
||||
+338
@@ -0,0 +1,338 @@
|
||||
.. index::
|
||||
single: Commands
|
||||
|
||||
コマンド
|
||||
########
|
||||
|
||||
Phinx は多くのコマンドを使用して実行されます。
|
||||
|
||||
マイグレーションコマンド
|
||||
========================
|
||||
|
||||
init コマンド
|
||||
----------------
|
||||
|
||||
init コマンド (initialize の略) は、Phinx のプロジェクトを準備するために使用されます。
|
||||
このコマンドはプロジェクトディレクトリーのルートに ``phinx.yml`` ファイルを生成します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ cd yourapp
|
||||
$ phinx init .
|
||||
|
||||
このファイルをテキストエディターで開き、プロジェクトの設定を行います。
|
||||
詳しくは :doc:`設定 <configuration>` の章をご覧下さい。
|
||||
|
||||
create コマンド
|
||||
---------------
|
||||
|
||||
create コマンドは、新しいマイグレーションファイルを作成するために使用されます。
|
||||
1つの引数、つまりマイグレーション名が必要です。
|
||||
マイグレーション名は、キャメルケース形式で指定する必要があります。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration
|
||||
|
||||
新しいマイグレーションファイルをテキストエディターで開き、データベースの変更を追加します。
|
||||
Phinx は ``phinx.yml`` ファイルで指定されたパスを使ってマイグレーションファイルを作成します。
|
||||
詳しくは :doc:`設定 <configuration>` の章をご覧下さい。
|
||||
|
||||
代替のテンプレートファイル名を指定することで、
|
||||
Phinx が使用するテンプレートファイルを上書きすることができます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --template="<file>"
|
||||
|
||||
テンプレート生成クラスを提供することもできます。このクラスはインタフェース
|
||||
``Phinx\Migration\CreationInterface`` を実装しなければなりません。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx create MyNewMigration --class="<class>"
|
||||
|
||||
マイグレーションのテンプレートを提供するだけでなく、クラスはマイグレーションファイルが
|
||||
テンプレートから生成されると呼び出されるコールバックを定義することもできます。
|
||||
|
||||
``--template`` と ``--class`` の両方を使用することはできません。
|
||||
|
||||
migrate コマンド
|
||||
----------------
|
||||
|
||||
migrate コマンドは、すべての使用可能なマイグレーションを実行します。
|
||||
オプションで特定のバージョンまで実行できます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development
|
||||
|
||||
特定のバージョンにマイグレーションするには、 ``--target`` パラメーターまたは省略して
|
||||
``-t`` を使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate -e development -t 20110103081132
|
||||
|
||||
``--dry-run`` を使って、クエリーを実行せずに標準出力に出力します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx migrate --dry-run
|
||||
|
||||
rollback コマンド
|
||||
-----------------
|
||||
|
||||
rollback コマンドは、Phinx によって実行された以前のマイグレーションを取り消すために使用されます。
|
||||
これは、migrate コマンドの反対です。
|
||||
|
||||
引数を指定せずに ``rollback`` コマンドを使用すると、以前の移行にロールバックすることができます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development
|
||||
|
||||
すべてのマイグレーションを特定のバージョンにロールバックするには、 ``--target`` パラメーターまたは
|
||||
省略して ``-t`` を使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 20120103083322
|
||||
|
||||
ターゲットバージョンとして 0 を指定すると、すべてのマイグレーションが元に戻ります。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0
|
||||
|
||||
すべてのマイグレーションを特定の日付にロールバックするには、 ``--date`` パラメーターまたは省略して
|
||||
``-d`` を省略して使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -d 2012
|
||||
$ phinx rollback -e development -d 201201
|
||||
$ phinx rollback -e development -d 20120103
|
||||
$ phinx rollback -e development -d 2012010312
|
||||
$ phinx rollback -e development -d 201201031205
|
||||
$ phinx rollback -e development -d 20120103120530
|
||||
|
||||
ブレークポイントが設定され、さらにロールバックをブロックしている場合は、 ``--force`` パラメーターまたは
|
||||
``-f`` を使ってブレークポイントをオーバーライドすることができます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback -e development -t 0 -f
|
||||
|
||||
``--dry-run`` を使って、クエリーを実行せずに標準出力に出力します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx rollback --dry-run
|
||||
|
||||
.. note::
|
||||
|
||||
ロールバックすると、Phinx は ``phinx.yml`` ファイルの ``version_order`` オプションで
|
||||
指定された順序で実行されたマイグレーションを処理します。
|
||||
詳しくは :doc:`設定 <configuration>` の章をご覧下さい。
|
||||
|
||||
status コマンド
|
||||
---------------
|
||||
|
||||
status コマンドは、すべてのマイグレーションのリストを現在のステータスとともに表示します。
|
||||
このコマンドを使用して、実行されたマイグレーションを確認できます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx status -e development
|
||||
|
||||
このコマンドは、データベースが最新の場合(つまり、すべてのマイグレーションが稼働している場合)
|
||||
コード0で終了します。またはそれ以外の場合は、次のコードのいずれかで終了します。
|
||||
|
||||
* 1: 実行されるマイグレーションが少なくとも1つ残っています。
|
||||
* 2: マイグレーションが実行され、データベースに記録されましたが、マイグレーションファイルが有りません。
|
||||
|
||||
breakpoint コマンド
|
||||
-------------------
|
||||
|
||||
breakpoint コマンドは、ブレークポイントを設定するために使用され、ロールバックを制限することができます。
|
||||
最新のマイグレーションのブレークポイントは、パラメーターを指定しないで切り替えることができます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development
|
||||
|
||||
特定のバージョンでブレークポイントを切り替えるには、 ``--target`` パラメーターまたは省略して
|
||||
``-t`` を使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -t 20120103083322
|
||||
|
||||
全てのブレークポイントを削除するには、 ``--remove-all`` パラメーターまたは省略して
|
||||
``-r`` を使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx breakpoint -e development -r
|
||||
|
||||
ブレークポイントは、 ``status`` コマンドを実行すると表示されます。
|
||||
|
||||
データベースの初期データ投入
|
||||
============================
|
||||
|
||||
seed:create コマンド
|
||||
--------------------
|
||||
|
||||
seed:create コマンドを使用して、新しいデータベースシードクラスを作成できます。
|
||||
1つの引数、クラスの名前が必要です。クラス名はキャメルケース形式で指定する必要があります。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:create MyNewSeeder
|
||||
|
||||
テキストエディターで新しいシードファイルを開き、データベースシードコマンドを追加します。
|
||||
Phinx は ``phinx.yml`` ファイルで指定されたパスを使ってシードファイルを作成します。
|
||||
詳しくは :doc:`設定 <configuration>` の章をご覧下さい。
|
||||
|
||||
seed:run コマンド
|
||||
-----------------
|
||||
|
||||
seed:run コマンドは、使用可能なすべてのシードクラスを実行するか、オプションで1つだけを実行します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development
|
||||
|
||||
シードクラスを1つだけ実行するには、 ``--seed`` パラメーターまたは省略して ``-s`` を使用します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ phinx seed:run -e development -s MyNewSeeder
|
||||
|
||||
設定ファイルパラメーター
|
||||
------------------------
|
||||
|
||||
コマンドラインから Phinx を実行するときは、 ``--configuration`` または
|
||||
``-c`` パラメーターを使って設定ファイルを指定することができます。
|
||||
YAML に加えて、設定ファイルは PHP 配列として PHP ファイルの計算された出力でもよいです。
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"adapter" => "mysql",
|
||||
"host" => $_ENV['DB_HOST'],
|
||||
"name" => $_ENV['DB_NAME'],
|
||||
"user" => $_ENV['DB_USER'],
|
||||
"pass" => $_ENV['DB_PASS'],
|
||||
"port" => $_ENV['DB_PORT'],
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
Phinx は ``*.yml`` と ``*.php`` 拡張子を持つファイルにどの言語パーサーを使うかを自動的に検出します。
|
||||
適切なパーサーは、 ``--parser`` と ``-p`` パラメーターで指定することもできます。
|
||||
``"php"`` 以外は YAML として扱われます。
|
||||
|
||||
PHP 配列を使用する場合、既存の PDO インスタンスに ``connection`` キーを提供することができます。
|
||||
Phinx は ``hasTable()`` のような特定のメソッドに対してデータベース名を必要とするため、
|
||||
データベース名も渡すことも重要です。
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
<?php
|
||||
return [
|
||||
"paths" => [
|
||||
"migrations" => "application/migrations"
|
||||
],
|
||||
"environments" => [
|
||||
"default_migration_table" => "phinxlog",
|
||||
"default_database" => "dev",
|
||||
"dev" => [
|
||||
"name" => "dev_db",
|
||||
"connection" => $pdo_instance
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
ウェブアプリ内で Phinx を実行
|
||||
-----------------------------
|
||||
|
||||
Phinx は ``Phinx\Wrapper\TextWrapper`` クラスを使ってウェブアプリケーションの内部で
|
||||
実行することもできます。この例は ``app/web.php`` で提供されています。
|
||||
これはスタンドアロンサーバーとして実行できます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php -S localhost:8000 vendor/robmorgan/phinx/app/web.php
|
||||
|
||||
これはデフォルトで現在のマイグレーションの状態を表示する `<http://localhost:8000>`__
|
||||
にローカルウェブサーバーを作成します。マイグレーションを実行するには、
|
||||
`<http://localhost:8000/migrate>`__ を使用し、ロールバックには
|
||||
`<http://localhost:8000/rollback>`__ を使用します。
|
||||
|
||||
**付属のウェブアプリは一例に過ぎません、本番環境では使用しないでください!**
|
||||
|
||||
.. note::
|
||||
|
||||
実行時に設定変数を変更し、 ``%%PHINX_DBNAME%%`` やその他の動的オプションを変更するには、
|
||||
コマンドを実行する前に ``$_SERVER['PHINX_DBNAME']`` を設定します。
|
||||
使用可能なオプションは、設定ページに記載されています。
|
||||
|
||||
PHPUnit で Phinx を使用
|
||||
-----------------------
|
||||
|
||||
Phinx は、ユニットテスト内でデータベースを準備またはシードするために使用できます。
|
||||
プログラムによって使用することができます。
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$app = new PhinxApplication();
|
||||
$app->setAutoExit(false);
|
||||
$app->run(new StringInput('migrate'), new NullOutput());
|
||||
}
|
||||
|
||||
メモリーデータベースを使用する場合は、Phinx に特定の PDO インスタンスを提供する必要があります。
|
||||
Manager クラスを使用して Phinx と直接対話することができます。
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use PDO;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Migration\Manager;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Symfony\Component\Console\Input\StringInput;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
|
||||
class DatabaseTestCase extends TestCase {
|
||||
|
||||
public function setUp ()
|
||||
{
|
||||
$pdo = new PDO('sqlite::memory:', null, null, [
|
||||
PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION
|
||||
]);
|
||||
$configArray = require('phinx.php');
|
||||
$configArray['environments']['test'] = [
|
||||
'adapter' => 'sqlite',
|
||||
'connection' => $pdo
|
||||
];
|
||||
$config = new Config($configArray);
|
||||
$manager = new Manager($config, new StringInput(' '), new NullOutput());
|
||||
$manager->migrate('test');
|
||||
$manager->seed('test');
|
||||
// シード後にデフォルトのフェッチモードを変更することができます
|
||||
$this->pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
|
||||
$this->pdo = $pdo;
|
||||
}
|
||||
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
import sys, os
|
||||
|
||||
# Append the top level directory of the docs, so we can import from the config dir.
|
||||
sys.path.insert(0, os.path.abspath('..'))
|
||||
|
||||
# Pull in all the configuration options defined in the global config file..
|
||||
from config.all import *
|
||||
|
||||
language = 'ja'
|
||||
+305
@@ -0,0 +1,305 @@
|
||||
.. index::
|
||||
single: Configuration
|
||||
|
||||
構成設定
|
||||
=============
|
||||
|
||||
:doc:`init コマンド <commands>` を使ってプロジェクトを初期化すると、
|
||||
Phinx はプロジェクトディレクトリーのルートに ``phinx.yml`` というデフォルトファイルを作成します。
|
||||
このファイルは、YAML データのシリアル化形式を使用します。
|
||||
|
||||
``--configuration`` コマンドラインオプションが与えられた場合、Phinx は指定されたファイルを
|
||||
ロードします。それ以外の場合は、 ``phinx.php`` 、 ``phinx.json`` または ``phinx.yml``
|
||||
を見つけて、最初に見つかったファイルを読み込みます。詳しくは、 :doc:`コマンド <commands>`
|
||||
の章をご覧下さい。
|
||||
|
||||
.. warning::
|
||||
|
||||
設定ファイルは、ウェブサーバー上の一般公開されているディレクトリーの外に保存してください。
|
||||
このファイルにはデータベースの信用情報が含まれており、
|
||||
誤ってプレーンテキストとして提供される可能性があります。
|
||||
|
||||
JSON ファイルと YAML ファイルは *パース* されますが、PHP ファイルは *インクルード* されています。
|
||||
つまり、こういうことです。
|
||||
|
||||
* 設定項目の配列を `return` する必要があります。
|
||||
* 変数スコープはローカルです。つまり、初期化ファイルが読み取ったり変更したりするグローバル変数を
|
||||
明示的に宣言する必要があります。
|
||||
* その標準出力は抑制されます。
|
||||
* JSON や YAML とは異なり、環境接続の詳細を省略し、代わりに初期化された PDO インスタンスを含む
|
||||
``connection`` を指定することができます。
|
||||
これは、マイグレーションがアプリケーションとやり取りしたり、同じ接続を共有したりする場合に便利です。
|
||||
ただし、Phinx は PDO 接続からデータベース名を推測できないため、データベース名を渡すことを
|
||||
忘れないでください。
|
||||
|
||||
::
|
||||
|
||||
<?php
|
||||
require 'app/init.php';
|
||||
|
||||
global $app;
|
||||
$pdo = $app->getDatabase()->getPdo();
|
||||
|
||||
return ['environments' =>
|
||||
[
|
||||
'default_database' => 'development',
|
||||
'development' => [
|
||||
'name' => 'devdb',
|
||||
'connection' => $pdo,
|
||||
]
|
||||
]
|
||||
];
|
||||
|
||||
マイグレーションのパス
|
||||
----------------------
|
||||
|
||||
最初のオプションは、マイグレーションのディレクトリーへのパスを指定します。
|
||||
デフォルトでは Phinx は ``%%PHINX_CONFIG_DIR%%/db/migrations`` を使用します。
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` は特別なトークンで、
|
||||
``phinx.yml`` ファイルが保存されているルートディレクトリーに自動的に置き換えられます。
|
||||
|
||||
デフォルトの ``%%PHINX_CONFIG_DIR%%/db/migrations`` を上書きするには、
|
||||
yaml 設定に次の行を追加する必要があります。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: /your/full/path
|
||||
|
||||
また、設定内の配列を使用して複数のマイグレーションパスを提供することもできます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations:
|
||||
- application/module1/migrations
|
||||
- application/module2/migrations
|
||||
|
||||
パスに ``%%PHINX_CONFIG_DIR%%`` トークンを使うこともできます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
マイグレーションは ``glob`` で取り込まれるので、複数のディレクトリーのパターンを定義することができます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
migrations: '%%PHINX_CONFIG_DIR%%/module/*/{data,scripts}/migrations'
|
||||
|
||||
カスタムベースクラス
|
||||
---------------------
|
||||
|
||||
デフォルトでは、すべてのマイグレーションは Phinx の ``AbstractMigration`` クラスを継承します。
|
||||
これは、設定の中で ``migration_base_class`` を設定することによって、 ``AbstractMigration``
|
||||
を継承したカスタムクラスに設定することができます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
migration_base_class: MyMagicalMigration
|
||||
|
||||
シードのパス
|
||||
------------
|
||||
|
||||
2番目のオプションは、シードディレクトリーへのパスを指定します。
|
||||
デフォルトでは Phinx は ``%%PHINX_CONFIG_DIR%%/db/seeds`` を使用します。
|
||||
|
||||
.. note::
|
||||
|
||||
``%%PHINX_CONFIG_DIR%%`` は特別なトークンで、
|
||||
``phinx.yml`` ファイルが保存されているルートディレクトリーに自動的に置き換えられます。
|
||||
|
||||
デフォルトの ``%%PHINX_CONFIG_DIR%%/db/seeds`` を上書きするには、
|
||||
yaml 設定に以下を追加する必要があります。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: /your/full/path
|
||||
|
||||
また、設定内で配列を使用して複数のシードパスを指定することもできます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds:
|
||||
- /your/full/path1
|
||||
- /your/full/path2
|
||||
|
||||
パスに ``%%PHINX_CONFIG_DIR%%`` トークンを使うこともできます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
paths:
|
||||
seeds: '%%PHINX_CONFIG_DIR%%/your/relative/path'
|
||||
|
||||
環境
|
||||
----
|
||||
|
||||
Phinx の主な機能の1つは、複数のデータベース環境をサポートすることです。Phinx を使用して、
|
||||
開発環境でマイグレーションを作成した後、本番環境で同じマイグレーションを実行することができます。
|
||||
環境は ``environments`` 以下にネストされたコレクションで指定されます。例:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: localhost
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
port: 3306
|
||||
charset: utf8
|
||||
collation: utf8_unicode_ci
|
||||
|
||||
上記は ``production`` と呼ばれる新しい環境を定義します。
|
||||
|
||||
複数の開発者が同じプロジェクトで作業し、それぞれが異なる環境を持つ状況
|
||||
(例えば、 ``<environment type>-<developer name>-<machine name>`` のような規約)、
|
||||
または、別々の目的(ブランチ、テストなど)のために別々の環境を持つ必要がある場合には、
|
||||
環境変数 `PHINX_ENVIRONMENT` を使用して yaml ファイルのデフォルト環境を上書きします。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
export PHINX_ENVIRONMENT=dev-`whoami`-`hostname`
|
||||
|
||||
テーブルのプレフィクスとサフィックス
|
||||
------------------------------------
|
||||
|
||||
テーブルのプレフィックスとサフィックスを定義することができます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
....
|
||||
table_prefix: dev_
|
||||
table_suffix: _v1
|
||||
testing:
|
||||
....
|
||||
table_prefix: test_
|
||||
table_suffix: _v2
|
||||
|
||||
ソケット接続
|
||||
------------
|
||||
|
||||
MySQL アダプターを使用する場合、ネットワーク接続の代わりにソケットを使用することもできます。
|
||||
ソケットのパスは ``unix_socket`` で設定されます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
name: production_db
|
||||
user: root
|
||||
pass: ''
|
||||
unix_socket: /var/run/mysql/mysql.sock
|
||||
charset: utf8
|
||||
|
||||
外部変数
|
||||
--------
|
||||
|
||||
Phinx は ``PHINX_`` というプレフィックスが付いた環境変数を自動的に取得し、
|
||||
設定ファイルのトークンとして利用できるようにします。
|
||||
トークンは変数とまったく同じ名前になりますが、どちらの側にも2つの
|
||||
``%%`` のシンボルをラップすることによってアクセスする必要があります。
|
||||
例: ``%%PHINX_DBUSER%%`` 。これは、秘密のデータベース資格情報をバージョン管理システムではなく
|
||||
サーバーに直接格納する場合に特に便利です。この機能は、次の例で簡単に実証できます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
default_migration_table: phinxlog
|
||||
default_database: development
|
||||
production:
|
||||
adapter: mysql
|
||||
host: '%%PHINX_DBHOST%%'
|
||||
name: '%%PHINX_DBNAME%%'
|
||||
user: '%%PHINX_DBUSER%%'
|
||||
pass: '%%PHINX_DBPASS%%'
|
||||
port: 3306
|
||||
charset: utf8
|
||||
|
||||
サポートするアダプター
|
||||
----------------------
|
||||
|
||||
Phinx は現在、次のデータベースアダプターをネイティブにサポートしています。
|
||||
|
||||
* `MySQL <http://www.mysql.com/>`_: ``mysql`` アダプターを指定。
|
||||
* `PostgreSQL <http://www.postgresql.org/>`_: ``pgsql`` アダプターを指定。
|
||||
* `SQLite <http://www.sqlite.org/>`_: ``sqlite`` アダプターを指定。
|
||||
* `SQL Server <http://www.microsoft.com/sqlserver>`_: ``sqlsrv`` アダプターを指定。
|
||||
|
||||
SQLite
|
||||
~~~~~~
|
||||
|
||||
SQLite データベースを宣言すると、単純化された構造が使用されます。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
environments:
|
||||
development:
|
||||
adapter: sqlite
|
||||
name: ./data/derby
|
||||
testing:
|
||||
adapter: sqlite
|
||||
memory: true # *任意* の値で memory を設定すると、 name が上書きされます
|
||||
|
||||
SQL Server
|
||||
~~~~~~~~~~
|
||||
|
||||
``sqlsrv`` アダプターを使用して名前付きインスタンスに接続するときは、
|
||||
SQL Server が自動的にポートをネゴシエートするので、 ``port`` 設定を省略してください。
|
||||
さらに、 ``charset: utf8`` を省略するか、SQL Server の UTF8 に対応する
|
||||
``charset: 65001`` に変更してください。
|
||||
|
||||
カスタムアダプター
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
``Phinx\\Db\\Adapter\\AdapterInterface`` の実装を ``AdapterFactory`` で登録することで
|
||||
カスタムアダプターを提供できます。
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$name = 'fizz';
|
||||
$class = 'Acme\Adapter\FizzAdapter';
|
||||
|
||||
AdapterFactory::instance()->registerAdapter($name, $class);
|
||||
|
||||
アダプターは `$app->run()` が呼び出される前にいつでも登録することができます。
|
||||
通常は `bin/phinx` によって呼び出されます。
|
||||
|
||||
エイリアス
|
||||
----------
|
||||
|
||||
テンプレート作成クラス名は、別名をつけて :doc:`create コマンド<commands>` の
|
||||
``--class`` コマンドラインオプションで使うことができます。
|
||||
|
||||
エイリアス化されたクラスは ``Phinx\Migration\CreationInterface`` インタフェースを実装する
|
||||
必要があります。
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
aliases:
|
||||
permission: \Namespace\Migrations\PermissionMigrationTemplateGenerator
|
||||
view: \Namespace\Migrations\ViewMigrationTemplateGenerator
|
||||
|
||||
バージョンの順序
|
||||
----------------
|
||||
|
||||
マイグレーションの状態をロールバックまたは表示するとき、Phinx は ``version_order``
|
||||
オプションに従って実行されたマイグレーションを処理します。これは次の値をとります。
|
||||
|
||||
* ``creation`` (デフォルト): マイグレーションはファイル名の一部でもある作成時間順に並べ替えられます。
|
||||
* ``execution``: マイグレーションは実行時間(開始時間とも呼ばれます)によって順序付けられます。
|
||||
+12
@@ -0,0 +1,12 @@
|
||||
コンテンツ
|
||||
===========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
:caption: Phinx
|
||||
|
||||
index
|
||||
migrations
|
||||
seeding
|
||||
commands
|
||||
configuration
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
Phinx マイグレーション
|
||||
######################
|
||||
|
||||
Phinx は、データベースのマイグレーションを管理するためのスタンドアロンのコマンドラインツールです。
|
||||
CakePHP の公式 Migrations プラグインはこのツールに基づいています。
|
||||
|
||||
Phinx は、あなたの PHP アプリケーションのデータベースマイグレーションを超簡単に管理できます。
|
||||
5分以内に、Composer を使用して Phinx をインストールし、最初のデータベースマイグレーションを作成できます。
|
||||
Phinx は、データベース ORM システムやアプリケーションフレームワークを使わずに、マイグレーションします。
|
||||
|
||||
はじめに
|
||||
============
|
||||
|
||||
良い開発者は常に SCM システムを使ってコードをバージョン管理します。それでは、なぜ、
|
||||
データベーススキーマについても同じことをしないのでしょうか?
|
||||
|
||||
Phinx は、開発者がデータベースを明確かつ簡潔な方法で変更および操作できるようにします。
|
||||
これは手作業で SQL を書くことを避け、代わりに PHP コードを使用してマイグレーションを作成するための
|
||||
強力な API を提供します。開発者は、好みの SCM システムを使用して、これらのマイグレーションを
|
||||
バージョン管理することができます。これにより、異なるデータベースシステム間で Phinx のマイグレーションを
|
||||
移植可能にします。Phinx はどのマイグレーションが実行されたかを把握しているので、
|
||||
データベースの状態については心配する必要はなく、より良いソフトウェアを構築することに
|
||||
集中することができます。
|
||||
|
||||
ゴール
|
||||
=======
|
||||
|
||||
Phinx は以下の目標を念頭に置いて開発されました。
|
||||
|
||||
* 最も普及しているデータベースベンダー間の可搬性。
|
||||
* PHP フレームワークに依存しない。
|
||||
* シンプルなインストール手順。
|
||||
* 使いやすいコマンドライン操作。
|
||||
* 他のさまざまな PHP ツール(Phing、PHPUnit)やウェブフレームワークとの統合。
|
||||
|
||||
インストール
|
||||
=============
|
||||
|
||||
Phinx は、PHP の依存関係管理のためのツールである Composer を使用してインストールする必要があります。
|
||||
詳しくは `Composer <https://getcomposer.org/>`_ のウェブサイトを見てください。
|
||||
|
||||
.. note::
|
||||
|
||||
Phinx には少なくともPHP 5.4(またはそれ以降)が必要です。
|
||||
|
||||
Phinx をインストールするには、Composer を使用する必要があります。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php composer.phar require robmorgan/phinx
|
||||
|
||||
適切なパーミッションを持つ ``db/migrations`` 構造に従って、プロジェクト内にフォルダーを作成します。
|
||||
これは、マイグレーションファイルが存在し、書き込み可能である場所です。
|
||||
|
||||
今、プロジェクト内から Phinx を実行できるようになりました。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
vendor/bin/phinx init
|
||||
|
||||
+1293
File diff suppressed because it is too large.
Load diff
+214
@@ -0,0 +1,214 @@
|
||||
.. index::
|
||||
single: Database Seeding
|
||||
|
||||
データベースの初期データ投入
|
||||
============================
|
||||
|
||||
バージョン0.5.0 では、Phinx はデータベースにテストデータをシードするためのサポートを導入しました。
|
||||
シードクラスは、作成済みのデータをデータベースに簡単に投入するための優れた方法です。
|
||||
デフォルトでは ``seeds`` ディレクトリーに保存されます。 ただし、このパスは設定ファイルで変更できます。
|
||||
|
||||
.. note::
|
||||
|
||||
データベースのシードは完全にオプションで、
|
||||
Phinx はデフォルトで ``seeds`` ディレクトリーを作成しません。
|
||||
|
||||
シードクラスの新規作成
|
||||
----------------------
|
||||
|
||||
Phinx には、新しいシードクラスを簡単に生成するコマンドが含まれています。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:create UserSeeder
|
||||
|
||||
複数のシードのパスを指定した場合は、新しいシードクラスを作成するパスを選択するように求められます。
|
||||
|
||||
以下は、スケルトンテンプレートを元にしています。 ::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class MyNewSeeder extends AbstractSeed
|
||||
{
|
||||
/**
|
||||
* Run Method.
|
||||
*
|
||||
* Write your database seeder using this method.
|
||||
*
|
||||
* More information on writing seeders is available here:
|
||||
* http://docs.phinx.org/en/latest/seeding.html
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
AbstractSeed クラス
|
||||
-------------------
|
||||
|
||||
すべての Phinx のシードは ``AbstractSeed`` クラスを継承します。
|
||||
このクラスは、シードクラスを作成するために必要なサポートを提供します。
|
||||
シードクラスは主にテストデータの挿入に使用されます。
|
||||
|
||||
run メソッド
|
||||
~~~~~~~~~~~~
|
||||
|
||||
run メソッドは、 `seed:run` コマンドを実行すると、Phinx によって自動的に呼び出されます。
|
||||
このメソッドを使用してテストデータを挿入してください。
|
||||
|
||||
.. note::
|
||||
|
||||
マイグレーションとは異なり、Phinx はどのシードクラスが実行されたかを把握していません。
|
||||
これは、データベースシーダーを繰り返し実行できることを意味します。
|
||||
開発時にはこのことに留意してください。
|
||||
|
||||
データの挿入
|
||||
------------
|
||||
|
||||
Table オブジェクトの使用
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
シードクラスは、使い慣れた ``Table`` オブジェクトを使ってデータを挿入することもできます。
|
||||
シードクラス内から ``table()`` メソッドを呼び出し、 ``insert()`` メソッドを使用して
|
||||
データを挿入することで、Table オブジェクトのインスタンスを取得できます。 ::
|
||||
|
||||
<?php
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class PostsSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->save();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
``save()`` メソッドを呼び出して、データをテーブルにコミットする必要があります。
|
||||
Phinx はデータをバッファリングします。
|
||||
|
||||
Faker ライブラリーとの統合
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
シードクラスですばらしい `Faker ライブラリー <https://github.com/fzaninotto/Faker>`_
|
||||
を使うのは簡単です。Composer を使用してインストールするだけです。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ composer require fzaninotto/faker
|
||||
|
||||
そして、シードクラスの中で、それを使用してください。 ::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$faker = Faker\Factory::create();
|
||||
$data = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$data[] = [
|
||||
'username' => $faker->userName,
|
||||
'password' => sha1($faker->password),
|
||||
'password_salt' => sha1('foo'),
|
||||
'email' => $faker->email,
|
||||
'first_name' => $faker->firstName,
|
||||
'last_name' => $faker->lastName,
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
];
|
||||
}
|
||||
|
||||
$this->insert('users', $data);
|
||||
}
|
||||
}
|
||||
|
||||
テーブルのデータ消去
|
||||
--------------------
|
||||
|
||||
データを挿入することに加えて、Phinx は SQL の ``TRUNCATE`` コマンドを使って
|
||||
テーブルを空にすることを容易にします。 ::
|
||||
|
||||
<?php
|
||||
|
||||
use Phinx\Seed\AbstractSeed;
|
||||
|
||||
class UserSeeder extends AbstractSeed
|
||||
{
|
||||
public function run()
|
||||
{
|
||||
$data = [
|
||||
[
|
||||
'body' => 'foo',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
],
|
||||
[
|
||||
'body' => 'bar',
|
||||
'created' => date('Y-m-d H:i:s'),
|
||||
]
|
||||
];
|
||||
|
||||
$posts = $this->table('posts');
|
||||
$posts->insert($data)
|
||||
->save();
|
||||
|
||||
// テーブルを空にします
|
||||
$posts->truncate();
|
||||
}
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
SQLite は ``TRUNCATE`` コマンドをネイティブにサポートしていないので、 ``DELETE FROM``
|
||||
が使用されています。テーブルのデータ消去後、 ``VACUUM`` コマンドを呼び出すことをお勧めします。
|
||||
Phinx はこれを自動的には行いません。
|
||||
|
||||
シードクラスの実行
|
||||
------------------
|
||||
|
||||
これは簡単な部分です。データベースをシードするには、 ``seed:run`` コマンドを使います。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run
|
||||
|
||||
デフォルトでは、Phinx は利用可能なすべてのシードクラスを実行します。
|
||||
特定のクラスを実行したい場合は、 ``-s`` パラメーターを使ってそのクラスの名前を渡します。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder
|
||||
|
||||
複数のシーダーを実行することもできます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -s UserSeeder -s PermissionSeeder -s LogSeeder
|
||||
|
||||
``-v`` パラメーターを使用して、より詳細な出力を表示することもできます。
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
$ php vendor/bin/phinx seed:run -v
|
||||
|
||||
Phinx のシード機能は、テストデータをデータベースに簡単かつ繰り返し挿入するための
|
||||
簡単なメカニズムを提供します。
|
||||
Vendored
+35
@@ -0,0 +1,35 @@
|
||||
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
|
||||
+450
@@ -0,0 +1,450 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Config;
|
||||
|
||||
use Closure;
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Phinx configuration class.
|
||||
*
|
||||
* @package Phinx
|
||||
* @author Rob Morgan
|
||||
*/
|
||||
class Config implements ConfigInterface, NamespaceAwareInterface
|
||||
{
|
||||
use NamespaceAwareTrait;
|
||||
|
||||
/**
|
||||
* The value that identifies a version order by creation time.
|
||||
*/
|
||||
const VERSION_ORDER_CREATION_TIME = 'creation';
|
||||
|
||||
/**
|
||||
* The value that identifies a version order by execution time.
|
||||
*/
|
||||
const VERSION_ORDER_EXECUTION_TIME = 'execution';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $values = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $configFilePath;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function __construct(array $configArray, $configFilePath = null)
|
||||
{
|
||||
$this->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 getAliases()
|
||||
{
|
||||
return !empty($this->values['aliases']) ? $this->values['aliases'] : [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getConfigFilePath()
|
||||
{
|
||||
return $this->configFilePath;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @throws \UnexpectedValueException
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the bootstrap file path
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getBootstrapFile()
|
||||
{
|
||||
if (!isset($this->values['paths']['bootstrap'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->values['paths']['bootstrap'];
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (strpos($varname, 'PHINX_') === 0) {
|
||||
$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
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
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]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,139 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Config;
|
||||
|
||||
use ArrayAccess;
|
||||
|
||||
/**
|
||||
* Phinx configuration interface.
|
||||
*
|
||||
* @package Phinx
|
||||
* @author Woody Gilk
|
||||
*/
|
||||
interface ConfigInterface extends ArrayAccess
|
||||
{
|
||||
/**
|
||||
* Returns the configuration for each environment.
|
||||
*
|
||||
* This method returns <code>null</code> if no environments exist.
|
||||
*
|
||||
* @return array|null
|
||||
*/
|
||||
public function getEnvironments();
|
||||
|
||||
/**
|
||||
* Returns the configuration for a given environment.
|
||||
*
|
||||
* This method returns <code>null</code> 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);
|
||||
|
||||
/**
|
||||
* Get all the aliased values.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAliases();
|
||||
|
||||
/**
|
||||
* 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();
|
||||
|
||||
/**
|
||||
* Get the bootstrap file path
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
public function getBootstrapFile();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Config;
|
||||
|
||||
/**
|
||||
* Config aware getNamespaceByPath method.
|
||||
*
|
||||
* @package Phinx\Config
|
||||
* @author Andrey N. Mokhov
|
||||
*/
|
||||
interface NamespaceAwareInterface
|
||||
{
|
||||
/**
|
||||
* Get Migration Namespace associated with path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMigrationNamespaceByPath($path);
|
||||
|
||||
/**
|
||||
* Get Seed Namespace associated with path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getSeedNamespaceByPath($path);
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Config;
|
||||
|
||||
/**
|
||||
* Trait implemented NamespaceAwareInterface.
|
||||
*
|
||||
* @package Phinx\Config
|
||||
* @author Andrey N. Mokhov
|
||||
*/
|
||||
trait NamespaceAwareTrait
|
||||
{
|
||||
/**
|
||||
* Gets the paths to search for migration files.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
abstract public function getMigrationPaths();
|
||||
|
||||
/**
|
||||
* Gets the paths to search for seed files.
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
abstract public function getSeedPaths();
|
||||
|
||||
/**
|
||||
* Search $needle in $haystack and return key associate with him.
|
||||
*
|
||||
* @param string $needle
|
||||
* @param array $haystack
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
protected function searchNamespace($needle, $haystack)
|
||||
{
|
||||
$needle = realpath($needle);
|
||||
$haystack = array_map('realpath', $haystack);
|
||||
|
||||
$key = array_search($needle, $haystack);
|
||||
|
||||
return is_string($key) ? trim($key, '\\') : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Migration Namespace associated with path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMigrationNamespaceByPath($path)
|
||||
{
|
||||
$paths = $this->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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Config\Config;
|
||||
use Phinx\Config\ConfigInterface;
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use Phinx\Migration\Manager;
|
||||
use Phinx\Util\Util;
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* Abstract command, contains bootstrapping info
|
||||
*
|
||||
* @author Rob Morgan <robbym@gmail.com>
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* Exit code for when command executes successfully
|
||||
* @var int
|
||||
*/
|
||||
const CODE_SUCCESS = 0;
|
||||
|
||||
/**
|
||||
* Exit code for when command hits a non-recoverable error during execution
|
||||
* @var int
|
||||
*/
|
||||
const CODE_ERROR = 1;
|
||||
|
||||
/**
|
||||
* Exit code for when status command is run and there are missing migrations
|
||||
* @var int
|
||||
*/
|
||||
const CODE_STATUS_MISSING = 2;
|
||||
|
||||
/**
|
||||
* Exit code for when status command is run and there are no missing migations,
|
||||
* but does have down migrations
|
||||
* @var int
|
||||
*/
|
||||
const CODE_STATUS_DOWN = 3;
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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);
|
||||
|
||||
if ($bootstrap = $this->getConfig()->getBootstrapFile()) {
|
||||
$output->writeln('<info>using bootstrap</info> .' . str_replace(getcwd(), '', realpath($bootstrap)) . ' ');
|
||||
Util::loadPhpFile($bootstrap);
|
||||
}
|
||||
|
||||
// report the paths
|
||||
$paths = $this->getConfig()->getMigrationPaths();
|
||||
|
||||
$output->writeln('<info>using migration paths</info> ');
|
||||
|
||||
foreach (Util::globAll($paths) as $path) {
|
||||
$output->writeln('<info> - ' . realpath($path) . '</info>');
|
||||
}
|
||||
|
||||
try {
|
||||
$paths = $this->getConfig()->getSeedPaths();
|
||||
|
||||
$output->writeln('<info>using seed paths</info> ');
|
||||
|
||||
foreach (Util::globAll($paths) as $path) {
|
||||
$output->writeln('<info> - ' . realpath($path) . '</info>');
|
||||
}
|
||||
} catch (UnexpectedValueException $e) {
|
||||
// do nothing as seeds are optional
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the config.
|
||||
*
|
||||
* @param \Phinx\Config\ConfigInterface $config
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
public function setManager(Manager $manager)
|
||||
{
|
||||
$this->manager = $manager;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the migration manager.
|
||||
*
|
||||
* @return \Phinx\Migration\Manager|null
|
||||
*/
|
||||
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('<info>using config file</info> .' . 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('<info>using config parser</info> ' . $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
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Breakpoint extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'breakpoint';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment.');
|
||||
|
||||
$this->setDescription('Manage breakpoints')
|
||||
->addOption('--target', '-t', InputOption::VALUE_REQUIRED, 'The version number to target for the breakpoint')
|
||||
->addOption('--set', '-s', InputOption::VALUE_NONE, 'Set the breakpoint')
|
||||
->addOption('--unset', '-u', InputOption::VALUE_NONE, 'Unset the breakpoint')
|
||||
->addOption('--remove-all', '-r', InputOption::VALUE_NONE, 'Remove all breakpoints')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>breakpoint</info> command allows you to toggle, set, or unset 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
|
||||
|
||||
<info>phinx breakpoint -e development</info>
|
||||
<info>phinx breakpoint -e development -t 20110103081132</info>
|
||||
<info>phinx breakpoint -e development -r</info>
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Toggle the breakpoint.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return int integer 0 on success, or an error code.
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->bootstrap($input, $output);
|
||||
|
||||
$environment = $input->getOption('environment');
|
||||
$version = $input->getOption('target');
|
||||
$removeAll = $input->getOption('remove-all');
|
||||
$set = $input->getOption('set');
|
||||
$unset = $input->getOption('unset');
|
||||
|
||||
if ($environment === null) {
|
||||
$environment = $this->getConfig()->getDefaultEnvironment();
|
||||
$output->writeln('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
|
||||
} else {
|
||||
$output->writeln('<info>using environment</info> ' . $environment);
|
||||
}
|
||||
|
||||
if (!$this->getConfig()->hasEnvironment($environment)) {
|
||||
$output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
if ($version && $removeAll) {
|
||||
throw new InvalidArgumentException('Cannot toggle a breakpoint and remove all breakpoints at the same time.');
|
||||
}
|
||||
|
||||
if (($set && $unset) || ($set && $removeAll) || ($unset && $removeAll)) {
|
||||
throw new InvalidArgumentException('Cannot use more than one of --set, --unset, or --remove-all at the same time.');
|
||||
}
|
||||
|
||||
if ($removeAll) {
|
||||
// Remove all breakpoints.
|
||||
$this->getManager()->removeBreakpoints($environment);
|
||||
} elseif ($set) {
|
||||
// Set the breakpoint.
|
||||
$this->getManager()->setBreakpoint($environment, $version);
|
||||
} elseif ($unset) {
|
||||
// Unset the breakpoint.
|
||||
$this->getManager()->unsetBreakpoint($environment, $version);
|
||||
} else {
|
||||
// Toggle the breakpoint.
|
||||
$this->getManager()->toggleBreakpoint($environment, $version);
|
||||
}
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,309 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Config\NamespaceAwareInterface;
|
||||
use Phinx\Util\Util;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
class Create extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'create';
|
||||
|
||||
/**
|
||||
* The name of the interface that any external template creation class is required to implement.
|
||||
*/
|
||||
const CREATION_INTERFACE = 'Phinx\Migration\CreationInterface';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->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
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
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 (count($paths) === 1) {
|
||||
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 int 0 on success
|
||||
*/
|
||||
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 ? (PHP_EOL . 'namespace ' . $namespace . ';' . PHP_EOL) : '',
|
||||
'$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('<info>using migration base class</info> ' . $classes['$useClassName']);
|
||||
|
||||
if (!empty($altTemplate)) {
|
||||
$output->writeln('<info>using alternative template</info> ' . $altTemplate);
|
||||
} elseif (!empty($creationClassName)) {
|
||||
$output->writeln('<info>using template creation class</info> ' . $creationClassName);
|
||||
} else {
|
||||
$output->writeln('<info>using default template</info>');
|
||||
}
|
||||
|
||||
$output->writeln('<info>created</info> ' . str_replace(getcwd() . DIRECTORY_SEPARATOR, '', $filePath));
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Init extends Command
|
||||
{
|
||||
const FILE_NAME = 'phinx';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'init';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
$this->setDescription('Initialize the application for Phinx')
|
||||
->addOption('--format', '-f', InputArgument::OPTIONAL, 'What format should we use to initialize?', 'yml')
|
||||
->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 Interface implemented by all input classes.
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output Interface implemented by all output classes.
|
||||
*
|
||||
* @return int 0 on success
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$path = $this->resolvePath($input);
|
||||
$format = strtolower($input->getOption('format'));
|
||||
$this->writeConfig($path, $format);
|
||||
|
||||
$output->writeln("<info>created</info> {$path}");
|
||||
|
||||
return AbstractCommand::CODE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return valid $path for Phinx's config file.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input Interface implemented by all input classes.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
protected function resolvePath(InputInterface $input)
|
||||
{
|
||||
// get the migration path from the config
|
||||
$path = (string)$input->getArgument('path');
|
||||
|
||||
$format = strtolower($input->getOption('format'));
|
||||
if (!in_array($format, ['yml', 'json', 'php'])) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid format "%s". Format must be either yml, json, or php.',
|
||||
$format
|
||||
));
|
||||
}
|
||||
|
||||
// Fallback
|
||||
if (!$path) {
|
||||
$path = getcwd() . DIRECTORY_SEPARATOR . self::FILE_NAME . '.' . $format;
|
||||
}
|
||||
|
||||
// Adding file name if necessary
|
||||
if (is_dir($path)) {
|
||||
$path .= DIRECTORY_SEPARATOR . self::FILE_NAME . '.' . $format;
|
||||
}
|
||||
|
||||
// Check if path is available
|
||||
$dirname = dirname($path);
|
||||
if (is_dir($dirname) && !is_file($path)) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
// Path is valid, but file already exists
|
||||
if (is_file($path)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Config file "%s" already exists.',
|
||||
$path
|
||||
));
|
||||
}
|
||||
|
||||
// Dir is invalid
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'Invalid path "%s" for config file.',
|
||||
$path
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes Phinx's config in provided $path
|
||||
*
|
||||
* @param string $path Config file's path.
|
||||
* @param string $format Format to use for config file
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function writeConfig($path, $format = 'yml')
|
||||
{
|
||||
// Check if dir is writable
|
||||
$dirname = dirname($path);
|
||||
if (!is_writable($dirname)) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'The directory "%s" is not writable',
|
||||
$dirname
|
||||
));
|
||||
}
|
||||
|
||||
// load the config template
|
||||
if (is_dir(__DIR__ . '/../../../data/Phinx')) {
|
||||
$contents = file_get_contents(__DIR__ . '/../../../data/Phinx/' . self::FILE_NAME . '.' . $format . '.dist');
|
||||
} elseif ($format === 'yml') {
|
||||
$contents = file_get_contents(__DIR__ . '/../../../../' . self::FILE_NAME . '.' . $format);
|
||||
} else {
|
||||
throw new RuntimeException(sprintf(
|
||||
'Could not find template for format "%s".',
|
||||
$format
|
||||
));
|
||||
}
|
||||
|
||||
if (file_put_contents($path, $contents) === false) {
|
||||
throw new RuntimeException(sprintf(
|
||||
'The file "%s" could not be written to',
|
||||
$path
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class ListAliases extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'list:aliases';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->setDescription('List template class aliases')
|
||||
->setHelp('The <info>list:aliases</info> command lists the migration template generation class aliases');
|
||||
}
|
||||
|
||||
/**
|
||||
* List migration template creation aliases.
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @return int 0 on success
|
||||
*/
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->bootstrap($input, $output);
|
||||
|
||||
$aliases = $this->config->getAliases();
|
||||
|
||||
if ($aliases) {
|
||||
$maxAliasLength = max(array_map('strlen', array_keys($aliases)));
|
||||
$maxClassLength = max(array_map('strlen', $aliases));
|
||||
$output->writeln(
|
||||
array_merge(
|
||||
[
|
||||
'',
|
||||
sprintf('%s %s', str_pad('Alias', $maxAliasLength), str_pad('Class', $maxClassLength)),
|
||||
sprintf('%s %s', str_repeat('=', $maxAliasLength), str_repeat('=', $maxClassLength)),
|
||||
],
|
||||
array_map(
|
||||
function ($alias, $class) use ($maxAliasLength, $maxClassLength) {
|
||||
return sprintf('%s %s', str_pad($alias, $maxAliasLength), str_pad($class, $maxClassLength));
|
||||
},
|
||||
array_keys($aliases),
|
||||
$aliases
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
'<error>No aliases defined in %s</error>',
|
||||
str_replace(getcwd(), '', realpath($this->config->getConfigFilePath()))
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use DateTime;
|
||||
use Exception;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Throwable;
|
||||
|
||||
class Migrate extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'migrate';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
|
||||
|
||||
$this->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')
|
||||
->addOption('--fake', null, InputOption::VALUE_NONE, "Mark any migrations selected as run, but don't actually execute them")
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>migrate</info> command runs all available migrations, optionally up to a specific version
|
||||
|
||||
<info>phinx migrate -e development</info>
|
||||
<info>phinx migrate -e development -t 20110103081132</info>
|
||||
<info>phinx migrate -e development -d 20110103</info>
|
||||
<info>phinx migrate -e development -v</info>
|
||||
|
||||
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');
|
||||
$fake = (bool)$input->getOption('fake');
|
||||
|
||||
if ($environment === null) {
|
||||
$environment = $this->getConfig()->getDefaultEnvironment();
|
||||
$output->writeln('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
|
||||
} else {
|
||||
$output->writeln('<info>using environment</info> ' . $environment);
|
||||
}
|
||||
|
||||
if (!$this->getConfig()->hasEnvironment($environment)) {
|
||||
$output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
$envOptions = $this->getConfig()->getEnvironment($environment);
|
||||
if (isset($envOptions['adapter'])) {
|
||||
$output->writeln('<info>using adapter</info> ' . $envOptions['adapter']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['wrapper'])) {
|
||||
$output->writeln('<info>using wrapper</info> ' . $envOptions['wrapper']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['name'])) {
|
||||
$output->writeln('<info>using database</info> ' . $envOptions['name']);
|
||||
} else {
|
||||
$output->writeln('<error>Could not determine database name! Please specify a database name in your config file.</error>');
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
if (isset($envOptions['table_prefix'])) {
|
||||
$output->writeln('<info>using table prefix</info> ' . $envOptions['table_prefix']);
|
||||
}
|
||||
if (isset($envOptions['table_suffix'])) {
|
||||
$output->writeln('<info>using table suffix</info> ' . $envOptions['table_suffix']);
|
||||
}
|
||||
|
||||
$versionOrder = $this->getConfig()->getVersionOrder();
|
||||
$output->writeln('<info>ordering by</info> ' . $versionOrder . ' time');
|
||||
|
||||
if ($fake) {
|
||||
$output->writeln('<comment>warning</comment> performing fake migrations');
|
||||
}
|
||||
|
||||
try {
|
||||
// run the migrations
|
||||
$start = microtime(true);
|
||||
if ($date !== null) {
|
||||
$this->getManager()->migrateToDateTime($environment, new DateTime($date), $fake);
|
||||
} else {
|
||||
$this->getManager()->migrate($environment, $version, $fake);
|
||||
}
|
||||
$end = microtime(true);
|
||||
} catch (Exception $e) {
|
||||
$output->writeln('<error>' . $e->__toString() . '</error>');
|
||||
|
||||
return self::CODE_ERROR;
|
||||
} catch (Throwable $e) {
|
||||
$output->writeln('<error>' . $e->__toString() . '</error>');
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use DateTime;
|
||||
use InvalidArgumentException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Rollback extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'rollback';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
|
||||
|
||||
$this->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')
|
||||
->addOption('--fake', null, InputOption::VALUE_NONE, "Mark any rollbacks selected as run, but don't actually execute them")
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>rollback</info> command reverts the last migration, or optionally up to a specific version
|
||||
|
||||
<info>phinx rollback -e development</info>
|
||||
<info>phinx rollback -e development -t 20111018185412</info>
|
||||
<info>phinx rollback -e development -d 20111018</info>
|
||||
<info>phinx rollback -e development -v</info>
|
||||
<info>phinx rollback -e development -t 20111018185412 -f</info>
|
||||
|
||||
If you have a breakpoint set, then you can rollback to target 0 and the rollbacks will stop at the breakpoint.
|
||||
<info>phinx rollback -e development -t 0 </info>
|
||||
|
||||
The <info>version_order</info> 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 <info>-d|--date</info> 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 int integer 0 on success, or an error code.
|
||||
*/
|
||||
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');
|
||||
$fake = (bool)$input->getOption('fake');
|
||||
|
||||
$config = $this->getConfig();
|
||||
|
||||
if ($environment === null) {
|
||||
$environment = $config->getDefaultEnvironment();
|
||||
$output->writeln('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
|
||||
} else {
|
||||
$output->writeln('<info>using environment</info> ' . $environment);
|
||||
}
|
||||
|
||||
if (!$this->getConfig()->hasEnvironment($environment)) {
|
||||
$output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
$envOptions = $config->getEnvironment($environment);
|
||||
if (isset($envOptions['adapter'])) {
|
||||
$output->writeln('<info>using adapter</info> ' . $envOptions['adapter']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['wrapper'])) {
|
||||
$output->writeln('<info>using wrapper</info> ' . $envOptions['wrapper']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['name'])) {
|
||||
$output->writeln('<info>using database</info> ' . $envOptions['name']);
|
||||
}
|
||||
|
||||
$versionOrder = $this->getConfig()->getVersionOrder();
|
||||
$output->writeln('<info>ordering by</info> ' . $versionOrder . ' time');
|
||||
|
||||
if ($fake) {
|
||||
$output->writeln('<comment>warning</comment> performing fake rollbacks');
|
||||
}
|
||||
|
||||
// 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, $fake);
|
||||
$end = microtime(true);
|
||||
|
||||
$output->writeln('');
|
||||
$output->writeln('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Target from Date
|
||||
*
|
||||
* @param string $date The date to convert to a target.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Config\NamespaceAwareInterface;
|
||||
use Phinx\Util\Util;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Question\ChoiceQuestion;
|
||||
use Symfony\Component\Console\Question\ConfirmationQuestion;
|
||||
|
||||
class SeedCreate extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'seed:create';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->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
|
||||
*
|
||||
* @throws \Exception
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
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 (count($paths) === 1) {
|
||||
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 int 0 on success
|
||||
*/
|
||||
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('<info>using seed base class</info> ' . $classes['$useClassName']);
|
||||
$output->writeln('<info>created</info> .' . str_replace(getcwd(), '', $filePath));
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class SeedRun extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'seed:run';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
|
||||
|
||||
$this->setDescription('Run database seeders')
|
||||
->addOption('--seed', '-s', InputOption::VALUE_REQUIRED | InputOption::VALUE_IS_ARRAY, 'What is the name of the seeder?')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>seed:run</info> command runs all available or individual seeders
|
||||
|
||||
<info>phinx seed:run -e development</info>
|
||||
<info>phinx seed:run -e development -s UserSeeder</info>
|
||||
<info>phinx seed:run -e development -s UserSeeder -s PermissionSeeder -s LogSeeder</info>
|
||||
<info>phinx seed:run -e development -v</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Run database seeders.
|
||||
*
|
||||
* @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);
|
||||
|
||||
$seedSet = $input->getOption('seed');
|
||||
$environment = $input->getOption('environment');
|
||||
|
||||
if ($environment === null) {
|
||||
$environment = $this->getConfig()->getDefaultEnvironment();
|
||||
$output->writeln('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
|
||||
} else {
|
||||
$output->writeln('<info>using environment</info> ' . $environment);
|
||||
}
|
||||
|
||||
if (!$this->getConfig()->hasEnvironment($environment)) {
|
||||
$output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
$envOptions = $this->getConfig()->getEnvironment($environment);
|
||||
if (isset($envOptions['adapter'])) {
|
||||
$output->writeln('<info>using adapter</info> ' . $envOptions['adapter']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['wrapper'])) {
|
||||
$output->writeln('<info>using wrapper</info> ' . $envOptions['wrapper']);
|
||||
}
|
||||
|
||||
if (isset($envOptions['name'])) {
|
||||
$output->writeln('<info>using database</info> ' . $envOptions['name']);
|
||||
} else {
|
||||
$output->writeln('<error>Could not determine database name! Please specify a database name in your config file.</error>');
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
if (isset($envOptions['table_prefix'])) {
|
||||
$output->writeln('<info>using table prefix</info> ' . $envOptions['table_prefix']);
|
||||
}
|
||||
if (isset($envOptions['table_suffix'])) {
|
||||
$output->writeln('<info>using table suffix</info> ' . $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('<comment>All Done. Took ' . sprintf('%.4fs', $end - $start) . '</comment>');
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class Status extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'status';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment.');
|
||||
|
||||
$this->setDescription('Show migration status')
|
||||
->addOption('--format', '-f', InputOption::VALUE_REQUIRED, 'The output format: text or json. Defaults to text.')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>status</info> command prints a list of all migrations, along with their current status
|
||||
|
||||
<info>phinx status -e development</info>
|
||||
<info>phinx status -e development -f json</info>
|
||||
|
||||
The <info>version_order</info> 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('<comment>warning</comment> no environment specified, defaulting to: ' . $environment);
|
||||
} else {
|
||||
$output->writeln('<info>using environment</info> ' . $environment);
|
||||
}
|
||||
|
||||
if (!$this->getConfig()->hasEnvironment($environment)) {
|
||||
$output->writeln(sprintf('<error>The environment "%s" does not exist</error>', $environment));
|
||||
|
||||
return self::CODE_ERROR;
|
||||
}
|
||||
|
||||
if ($format !== null) {
|
||||
$output->writeln('<info>using format</info> ' . $format);
|
||||
}
|
||||
|
||||
$output->writeln('<info>ordering by </info>' . $this->getConfig()->getVersionOrder() . " time");
|
||||
|
||||
// print the status
|
||||
$result = $this->getManager()->printStatus($environment, $format);
|
||||
|
||||
if ($result['hasMissingMigration']) {
|
||||
return self::CODE_STATUS_MISSING;
|
||||
} elseif ($result['hasDownMigration']) {
|
||||
return self::CODE_STATUS_DOWN;
|
||||
}
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console\Command;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Migration\Manager\Environment;
|
||||
use Phinx\Util\Util;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* @author Leonid Kuzmin <lndkuzmin@gmail.com>
|
||||
*/
|
||||
class Test extends AbstractCommand
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected static $defaultName = 'test';
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function configure()
|
||||
{
|
||||
parent::configure();
|
||||
|
||||
$this->addOption('--environment', '-e', InputOption::VALUE_REQUIRED, 'The target environment');
|
||||
|
||||
$this->setDescription('Verify the configuration file')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>test</info> command verifies the YAML configuration file and optionally an environment
|
||||
|
||||
<info>phinx test</info>
|
||||
<info>phinx test -e development</info>
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify configuration file
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return int 0 on success
|
||||
*/
|
||||
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('<info>validating environment</info> %s', $envName));
|
||||
$environment = new Environment(
|
||||
$envName,
|
||||
$this->getConfig()->getEnvironment($envName)
|
||||
);
|
||||
// validate environment connection
|
||||
$environment->getAdapter()->connect();
|
||||
}
|
||||
|
||||
$output->writeln('<info>success!</info>');
|
||||
|
||||
return self::CODE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Console;
|
||||
|
||||
use Phinx\Console\Command\Breakpoint;
|
||||
use Phinx\Console\Command\Create;
|
||||
use Phinx\Console\Command\Init;
|
||||
use Phinx\Console\Command\ListAliases;
|
||||
use Phinx\Console\Command\Migrate;
|
||||
use Phinx\Console\Command\Rollback;
|
||||
use Phinx\Console\Command\SeedCreate;
|
||||
use Phinx\Console\Command\SeedRun;
|
||||
use Phinx\Console\Command\Status;
|
||||
use Phinx\Console\Command\Test;
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Phinx console application.
|
||||
*
|
||||
* @author Rob Morgan <robbym@gmail.com>
|
||||
*/
|
||||
class PhinxApplication extends Application
|
||||
{
|
||||
/**
|
||||
* Initialize the Phinx console application.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('Phinx by CakePHP - https://phinx.org.');
|
||||
|
||||
$this->addCommands([
|
||||
new Init(),
|
||||
new Create(),
|
||||
new Migrate(),
|
||||
new Rollback(),
|
||||
new Status(),
|
||||
new Breakpoint(),
|
||||
new Test(),
|
||||
new SeedCreate(),
|
||||
new SeedRun(),
|
||||
new ListAliases(),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 && $input->getFirstArgument() !== 'list')) {
|
||||
$output->writeln($this->getLongVersion());
|
||||
$output->writeln('');
|
||||
}
|
||||
|
||||
return parent::doRun($input, $output);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
abstract class Action
|
||||
{
|
||||
/**
|
||||
* @var \Phinx\Db\Table\Table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table the Table to apply the action to
|
||||
*/
|
||||
public function __construct(Table $table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* The table this action will be applied to
|
||||
*
|
||||
* @return \Phinx\Db\Table\Table
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class AddColumn extends Action
|
||||
{
|
||||
/**
|
||||
* The column to add
|
||||
*
|
||||
* @var \Phinx\Db\Table\Column
|
||||
*/
|
||||
protected $column;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the column to
|
||||
* @param \Phinx\Db\Table\Column $column The column to add
|
||||
*/
|
||||
public function __construct(Table $table, Column $column)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->column = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a new AddColumn object after assembling the given commands
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the column to
|
||||
* @param mixed $columnName The column name
|
||||
* @param mixed $type The column type
|
||||
* @param mixed $options The column options
|
||||
*
|
||||
* @return \Phinx\Db\Action\AddColumn
|
||||
*/
|
||||
public static function build(Table $table, $columnName, $type = null, $options = [])
|
||||
{
|
||||
$column = new Column();
|
||||
$column->setName($columnName);
|
||||
$column->setType($type);
|
||||
$column->setOptions($options); // map options to column methods
|
||||
|
||||
return new static($table, $column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column to be added
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column
|
||||
*/
|
||||
public function getColumn()
|
||||
{
|
||||
return $this->column;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\ForeignKey;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class AddForeignKey extends Action
|
||||
{
|
||||
/**
|
||||
* The foreign key to add
|
||||
*
|
||||
* @var \Phinx\Db\Table\ForeignKey
|
||||
*/
|
||||
protected $foreignKey;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the foreign key to
|
||||
* @param \Phinx\Db\Table\ForeignKey $fk The foreign key to add
|
||||
*/
|
||||
public function __construct(Table $table, ForeignKey $fk)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->foreignKey = $fk;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AddForeignKey object after building the foreign key with
|
||||
* the passed attributes
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table object to add the foreign key to
|
||||
* @param string|string[] $columns The columns for the foreign key
|
||||
* @param \Phinx\Db\Table\Table|string $referencedTable The table the foreign key references
|
||||
* @param string|array $referencedColumns The columns in the referenced table
|
||||
* @param array $options Extra options for the foreign key
|
||||
* @param string|null $name The name of the foreign key
|
||||
*
|
||||
* @return \Phinx\Db\Action\AddForeignKey
|
||||
*/
|
||||
public static function build(Table $table, $columns, $referencedTable, $referencedColumns = ['id'], array $options = [], $name = null)
|
||||
{
|
||||
if (is_string($referencedColumns)) {
|
||||
$referencedColumns = [$referencedColumns]; // str to array
|
||||
}
|
||||
|
||||
if (is_string($referencedTable)) {
|
||||
$referencedTable = new Table($referencedTable);
|
||||
}
|
||||
|
||||
$fk = new ForeignKey();
|
||||
$fk->setReferencedTable($referencedTable)
|
||||
->setColumns($columns)
|
||||
->setReferencedColumns($referencedColumns)
|
||||
->setOptions($options);
|
||||
|
||||
if ($name !== null) {
|
||||
$fk->setConstraint($name);
|
||||
}
|
||||
|
||||
return new static($table, $fk);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the foreign key to be added
|
||||
*
|
||||
* @return \Phinx\Db\Table\ForeignKey
|
||||
*/
|
||||
public function getForeignKey()
|
||||
{
|
||||
return $this->foreignKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class AddIndex extends Action
|
||||
{
|
||||
/**
|
||||
* The index to add to the table
|
||||
*
|
||||
* @var \Phinx\Db\Table\Index
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the index to
|
||||
* @param \Phinx\Db\Table\Index $index The index to be added
|
||||
*/
|
||||
public function __construct(Table $table, Index $index)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new AddIndex object after building the index object with the
|
||||
* provided arguments
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the index to
|
||||
* @param mixed $columns The columns to index
|
||||
* @param array $options Additional options for the index creation
|
||||
*
|
||||
* @return \Phinx\Db\Action\AddIndex
|
||||
*/
|
||||
public static function build(Table $table, $columns, array $options = [])
|
||||
{
|
||||
// create a new index object if strings or an array of strings were supplied
|
||||
$index = $columns;
|
||||
|
||||
if (!$columns instanceof Index) {
|
||||
$index = new Index();
|
||||
|
||||
if (is_string($columns)) {
|
||||
$columns = [$columns]; // str to array
|
||||
}
|
||||
|
||||
$index->setColumns($columns);
|
||||
$index->setOptions($options);
|
||||
}
|
||||
|
||||
return new static($table, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index to be added
|
||||
*
|
||||
* @return \Phinx\Db\Table\Index
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class ChangeColumn extends Action
|
||||
{
|
||||
/**
|
||||
* The column definition
|
||||
*
|
||||
* @var \Phinx\Db\Table\Column
|
||||
*/
|
||||
protected $column;
|
||||
|
||||
/**
|
||||
* The name of the column to be changed
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $columnName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to alter
|
||||
* @param mixed $columnName The name fo the column to change
|
||||
* @param \Phinx\Db\Table\Column $column The column definition
|
||||
*/
|
||||
public function __construct(Table $table, $columnName, Column $column)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->columnName = $columnName;
|
||||
$this->column = $column;
|
||||
|
||||
// if the name was omitted use the existing column name
|
||||
if ($column->getName() === null || strlen($column->getName()) === 0) {
|
||||
$column->setName($columnName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ChangeColumn object after building the column definition
|
||||
* out of the provided arguments
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to alter
|
||||
* @param mixed $columnName The name of the column to change
|
||||
* @param mixed $type The type of the column
|
||||
* @param mixed $options Additional options for the column
|
||||
*
|
||||
* @return \Phinx\Db\Action\ChangeColumn
|
||||
*/
|
||||
public static function build(Table $table, $columnName, $type = null, $options = [])
|
||||
{
|
||||
$column = new Column();
|
||||
$column->setName($columnName);
|
||||
$column->setType($type);
|
||||
$column->setOptions($options); // map options to column methods
|
||||
|
||||
return new static($table, $columnName, $column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the name of the column to change
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getColumnName()
|
||||
{
|
||||
return $this->columnName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column definition
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column
|
||||
*/
|
||||
public function getColumn()
|
||||
{
|
||||
return $this->column;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class ChangeComment extends Action
|
||||
{
|
||||
/**
|
||||
* The new comment for the table
|
||||
*
|
||||
* @var string|null
|
||||
*/
|
||||
protected $newComment;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to be changed
|
||||
* @param string|null $newComment The new comment for the table
|
||||
*/
|
||||
public function __construct(Table $table, $newComment)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->newComment = $newComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new comment for the table
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getNewComment()
|
||||
{
|
||||
return $this->newComment;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class ChangePrimaryKey extends Action
|
||||
{
|
||||
/**
|
||||
* The new columns for the primary key
|
||||
*
|
||||
* @var string|array|null
|
||||
*/
|
||||
protected $newColumns;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to be changed
|
||||
* @param string|array|null $newColumns The new columns for the primary key
|
||||
*/
|
||||
public function __construct(Table $table, $newColumns)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->newColumns = $newColumns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new columns for the primary key
|
||||
*
|
||||
* @return string|array|null
|
||||
*/
|
||||
public function getNewColumns()
|
||||
{
|
||||
return $this->newColumns;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
class CreateTable extends Action
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\ForeignKey;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class DropForeignKey extends Action
|
||||
{
|
||||
/**
|
||||
* The foreign key to remove
|
||||
*
|
||||
* @var \Phinx\Db\Table\ForeignKey
|
||||
*/
|
||||
protected $foreignKey;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to remove the constraint from
|
||||
* @param \Phinx\Db\Table\ForeignKey $foreignKey The foreign key to remove
|
||||
*/
|
||||
public function __construct(Table $table, ForeignKey $foreignKey)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->foreignKey = $foreignKey;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DropForeignKey object after building the ForeignKey
|
||||
* definition out of the passed arguments.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to delete the foreign key from
|
||||
* @param string|string[] $columns The columns participating in the foreign key
|
||||
* @param string|null $constraint The constraint name
|
||||
*
|
||||
* @return \Phinx\Db\Action\DropForeignKey
|
||||
*/
|
||||
public static function build(Table $table, $columns, $constraint = null)
|
||||
{
|
||||
if (is_string($columns)) {
|
||||
$columns = [$columns];
|
||||
}
|
||||
|
||||
$foreignKey = new ForeignKey();
|
||||
$foreignKey->setColumns($columns);
|
||||
|
||||
if ($constraint) {
|
||||
$foreignKey->setConstraint($constraint);
|
||||
}
|
||||
|
||||
return new static($table, $foreignKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the foreign key to remove
|
||||
*
|
||||
* @return \Phinx\Db\Table\ForeignKey
|
||||
*/
|
||||
public function getForeignKey()
|
||||
{
|
||||
return $this->foreignKey;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class DropIndex extends Action
|
||||
{
|
||||
/**
|
||||
* The index to drop
|
||||
*
|
||||
* @var \Phinx\Db\Table\Index
|
||||
*/
|
||||
protected $index;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table owning the index
|
||||
* @param \Phinx\Db\Table\Index $index The index to be dropped
|
||||
*/
|
||||
public function __construct(Table $table, Index $index)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->index = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DropIndex object after assembling the passed
|
||||
* arguments.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the index is
|
||||
* @param array $columns the indexed columns
|
||||
*
|
||||
* @return \Phinx\Db\Action\DropIndex
|
||||
*/
|
||||
public static function build(Table $table, array $columns = [])
|
||||
{
|
||||
$index = new Index();
|
||||
$index->setColumns($columns);
|
||||
|
||||
return new static($table, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new DropIndex when the name of the index to drop
|
||||
* is known.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the index is
|
||||
* @param mixed $name The name of the index
|
||||
*
|
||||
* @return \Phinx\Db\Action\DropIndex
|
||||
*/
|
||||
public static function buildFromName(Table $table, $name)
|
||||
{
|
||||
$index = new Index();
|
||||
$index->setName($name);
|
||||
|
||||
return new static($table, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index to be dropped
|
||||
*
|
||||
* @return \Phinx\Db\Table\Index
|
||||
*/
|
||||
public function getIndex()
|
||||
{
|
||||
return $this->index;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
class DropTable extends Action
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class RemoveColumn extends Action
|
||||
{
|
||||
/**
|
||||
* The column to be removed
|
||||
*
|
||||
* @var \Phinx\Db\Table\Column
|
||||
*/
|
||||
protected $column;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the column is
|
||||
* @param \Phinx\Db\Table\Column $column The column to be removed
|
||||
*/
|
||||
public function __construct(Table $table, Column $column)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->column = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RemoveColumn object after assembling the
|
||||
* passed arguments.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the column is
|
||||
* @param mixed $columnName The name of the column to drop
|
||||
*
|
||||
* @return \Phinx\Db\Action\RemoveColumn
|
||||
*/
|
||||
public static function build(Table $table, $columnName)
|
||||
{
|
||||
$column = new Column();
|
||||
$column->setName($columnName);
|
||||
|
||||
return new static($table, $column);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column to be dropped
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column
|
||||
*/
|
||||
public function getColumn()
|
||||
{
|
||||
return $this->column;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class RenameColumn extends Action
|
||||
{
|
||||
/**
|
||||
* The column to be renamed
|
||||
*
|
||||
* @var \Phinx\Db\Table\Column
|
||||
*/
|
||||
protected $column;
|
||||
|
||||
/**
|
||||
* The new name for the column
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $newName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the column is
|
||||
* @param \Phinx\Db\Table\Column $column The column to be renamed
|
||||
* @param mixed $newName The new name for the column
|
||||
*/
|
||||
public function __construct(Table $table, Column $column, $newName)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->newName = $newName;
|
||||
$this->column = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new RenameColumn object after building the passed
|
||||
* arguments
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table where the column is
|
||||
* @param mixed $columnName The name of the column to be changed
|
||||
* @param mixed $newName The new name for the column
|
||||
*
|
||||
* @return \Phinx\Db\Action\RenameColumn
|
||||
*/
|
||||
public static function build(Table $table, $columnName, $newName)
|
||||
{
|
||||
$column = new Column();
|
||||
$column->setName($columnName);
|
||||
|
||||
return new static($table, $column, $newName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the column to be changed
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column
|
||||
*/
|
||||
public function getColumn()
|
||||
{
|
||||
return $this->column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the new name for the column
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNewName()
|
||||
{
|
||||
return $this->newName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Action;
|
||||
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
class RenameTable extends Action
|
||||
{
|
||||
/**
|
||||
* The new name for the table
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $newName;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to be renamed
|
||||
* @param mixed $newName The new name for the table
|
||||
*/
|
||||
public function __construct(Table $table, $newName)
|
||||
{
|
||||
parent::__construct($table);
|
||||
$this->newName = $newName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the new name for the table
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getNewName()
|
||||
{
|
||||
return $this->newName;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use Exception;
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Db\Table;
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Util\Literal;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\NullOutput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Base Abstract Database Adapter.
|
||||
*/
|
||||
abstract class AbstractAdapter implements AdapterInterface
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options = [];
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Input\InputInterface
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected $createdTables = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $schemaTableName = 'phinxlog';
|
||||
|
||||
/**
|
||||
* @param array $options Options
|
||||
* @param \Symfony\Component\Console\Input\InputInterface|null $input Input Interface
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface|null $output Output Interface
|
||||
*/
|
||||
public function __construct(array $options, InputInterface $input = null, OutputInterface $output = null)
|
||||
{
|
||||
$this->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}
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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(),
|
||||
(int)$exception->getCode(),
|
||||
$exception
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAdapterType()
|
||||
{
|
||||
return $this->getOption('adapter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function isValidColumnType(Column $column)
|
||||
{
|
||||
return $column->getType() instanceof Literal || 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')) ? (bool)$input->getOption('dry-run') : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds user-created tables (e.g. not phinxlog) to a cached list
|
||||
*
|
||||
* @param string $tableName The name of the table
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function addCreatedTable($tableName)
|
||||
{
|
||||
if (substr_compare($tableName, 'phinxlog', -strlen('phinxlog')) !== 0) {
|
||||
$this->createdTables[] = $tableName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the name of the cached table
|
||||
*
|
||||
* @param string $tableName Original name of the table
|
||||
* @param string $newTableName New name of the table
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function updateCreatedTableName($tableName, $newTableName)
|
||||
{
|
||||
$key = array_search($tableName, $this->createdTables);
|
||||
if ($key !== false) {
|
||||
$this->createdTables[$key] = $newTableName;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes table from the cached created list
|
||||
*
|
||||
* @param string $tableName The name of the table
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function removeCreatedTable($tableName)
|
||||
{
|
||||
$key = array_search($tableName, $this->createdTables);
|
||||
if ($key !== false) {
|
||||
unset($this->createdTables[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the table is in the cached list of created tables
|
||||
*
|
||||
* @param string $tableName The name of the table
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
protected function hasCreatedTable($tableName)
|
||||
{
|
||||
return in_array($tableName, $this->createdTables);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,180 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Adapter factory and registry.
|
||||
*
|
||||
* Used for registering adapters and creating instances of adapters.
|
||||
*
|
||||
* @author Woody Gilk <woody.gilk@gmail.com>
|
||||
*/
|
||||
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.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $class
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param string $name
|
||||
* @param string $class
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @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.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,520 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
use Phinx\Migration\MigrationInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Adapter Interface.
|
||||
*
|
||||
* @author Rob Morgan <robbym@gmail.com>
|
||||
* @method \PDO getConnection()
|
||||
*/
|
||||
interface AdapterInterface
|
||||
{
|
||||
const PHINX_TYPE_STRING = 'string';
|
||||
const PHINX_TYPE_CHAR = 'char';
|
||||
const PHINX_TYPE_TEXT = 'text';
|
||||
const PHINX_TYPE_SMALL_INTEGER = 'smallinteger';
|
||||
const PHINX_TYPE_INTEGER = 'integer';
|
||||
const PHINX_TYPE_BIG_INTEGER = 'biginteger';
|
||||
const PHINX_TYPE_BIT = 'bit';
|
||||
const PHINX_TYPE_FLOAT = 'float';
|
||||
const PHINX_TYPE_DECIMAL = 'decimal';
|
||||
const PHINX_TYPE_DOUBLE = 'double';
|
||||
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();
|
||||
|
||||
/**
|
||||
* Set a migration breakpoint.
|
||||
*
|
||||
* @param \Phinx\Migration\MigrationInterface $migration The migration target for the breakpoint set
|
||||
*
|
||||
* @return \Phinx\Db\Adapter\AdapterInterface
|
||||
*/
|
||||
public function setBreakpoint(MigrationInterface $migration);
|
||||
|
||||
/**
|
||||
* Unset a migration breakpoint.
|
||||
*
|
||||
* @param \Phinx\Migration\MigrationInterface $migration The migration target for the breakpoint unset
|
||||
*
|
||||
* @return \Phinx\Db\Adapter\AdapterInterface
|
||||
*/
|
||||
public function unsetBreakpoint(MigrationInterface $migration);
|
||||
|
||||
/**
|
||||
* 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 list of migration actions for the given table
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to execute the actions for
|
||||
* @param \Phinx\Db\Action\Action[] $actions The table to execute the actions for
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeActions(Table $table, array $actions);
|
||||
|
||||
/**
|
||||
* Returns a new Query object
|
||||
*
|
||||
* @return \Cake\Database\Query
|
||||
*/
|
||||
public function getQueryBuilder();
|
||||
|
||||
/**
|
||||
* 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 $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 $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 Table
|
||||
* @param \Phinx\Db\Table\Column[] $columns List of columns in the table
|
||||
* @param \Phinx\Db\Table\Index[] $indexes List of indexes for the table
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createTable(Table $table, array $columns = [], array $indexes = []);
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Checks to see if an index exists.
|
||||
*
|
||||
* @param string $tableName Table Name
|
||||
* @param string|string[] $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);
|
||||
|
||||
/**
|
||||
* Checks to see if the specified primary key exists.
|
||||
*
|
||||
* @param string $tableName Table Name
|
||||
* @param string|string[] $columns Column(s)
|
||||
* @param string|null $constraint Constraint name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPrimaryKey($tableName, $columns, $constraint = null);
|
||||
|
||||
/**
|
||||
* Checks to see if a foreign key exists.
|
||||
*
|
||||
* @param string $tableName
|
||||
* @param string|string[] $columns Column(s)
|
||||
* @param string|null $constraint Constraint name
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasForeignKey($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|null $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);
|
||||
}
|
||||
@@ -0,0 +1,516 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table;
|
||||
use Phinx\Migration\MigrationInterface;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Adapter Wrapper.
|
||||
*
|
||||
* Proxy commands through to another adapter, allowing modification of
|
||||
* parameters during calls.
|
||||
*
|
||||
* @author Woody Gilk <woody.gilk@gmail.com>
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function connect()
|
||||
{
|
||||
$this->getAdapter()->connect();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert(Table $table, $row)
|
||||
{
|
||||
$this->getAdapter()->insert($table, $row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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 setBreakpoint(MigrationInterface $migration)
|
||||
{
|
||||
$this->getAdapter()->setBreakpoint($migration);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function unsetBreakpoint(MigrationInterface $migration)
|
||||
{
|
||||
$this->getAdapter()->unsetBreakpoint($migration);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasSchemaTable()
|
||||
{
|
||||
return $this->getAdapter()->hasSchemaTable();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function beginTransaction()
|
||||
{
|
||||
$this->getAdapter()->beginTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function commitTransaction()
|
||||
{
|
||||
$this->getAdapter()->commitTransaction();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createTable(Table $table, array $columns = [], array $indexes = [])
|
||||
{
|
||||
$this->getAdapter()->createTable($table, $columns, $indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 hasIndex($tableName, $columns)
|
||||
{
|
||||
return $this->getAdapter()->hasIndex($tableName, $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasIndexByName($tableName, $indexName)
|
||||
{
|
||||
return $this->getAdapter()->hasIndexByName($tableName, $indexName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasPrimaryKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
return $this->getAdapter()->hasPrimaryKey($tableName, $columns, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasForeignKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
return $this->getAdapter()->hasForeignKey($tableName, $columns, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getSqlType($type, $limit = null)
|
||||
{
|
||||
return $this->getAdapter()->getSqlType($type, $limit);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createDatabase($name, $options = [])
|
||||
{
|
||||
$this->getAdapter()->createDatabase($name, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasDatabase($name)
|
||||
{
|
||||
return $this->getAdapter()->hasDatabase($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropDatabase($name)
|
||||
{
|
||||
$this->getAdapter()->dropDatabase($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createSchema($schemaName = 'public')
|
||||
{
|
||||
$this->getAdapter()->createSchema($schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropSchema($schemaName)
|
||||
{
|
||||
$this->getAdapter()->dropSchema($schemaName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function truncateTable($tableName)
|
||||
{
|
||||
$this->getAdapter()->truncateTable($tableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function castToBool($value)
|
||||
{
|
||||
return $this->getAdapter()->castToBool($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getConnection()
|
||||
{
|
||||
return $this->getAdapter()->getConnection();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeActions(Table $table, array $actions)
|
||||
{
|
||||
$this->getAdapter()->executeActions($table, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getQueryBuilder()
|
||||
{
|
||||
return $this->getAdapter()->getQueryBuilder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\ForeignKey;
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
/**
|
||||
* Represents an adapter that is capable of directly executing alter
|
||||
* instructions, without having to plan them first.
|
||||
*/
|
||||
interface DirectActionInterface
|
||||
{
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* Changes the primary key of the specified database table.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table Table
|
||||
* @param string|array|null $newColumns Column name(s) to belong to the primary key, or null to drop the key
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changePrimaryKey(Table $table, $newColumns);
|
||||
|
||||
/**
|
||||
* Changes the comment of the specified database table.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table Table
|
||||
* @param string|null $newComment New comment string, or null to drop the comment
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeComment(Table $table, $newComment);
|
||||
|
||||
/**
|
||||
* Adds the specified column to a database table.
|
||||
*
|
||||
* @param \Phinx\Db\Table\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 void
|
||||
*/
|
||||
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);
|
||||
|
||||
/**
|
||||
* Adds the specified index to a database table.
|
||||
*
|
||||
* @param \Phinx\Db\Table\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 the name of the table
|
||||
* @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 The table name where the index is
|
||||
* @param string $indexName The name of the index
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropIndexByName($tableName, $indexName);
|
||||
|
||||
/**
|
||||
* Adds the specified foreign key to a database table.
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to add the foreign key to
|
||||
* @param \Phinx\Db\Table\ForeignKey $foreignKey The foreign key to add
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addForeignKey(Table $table, ForeignKey $foreignKey);
|
||||
|
||||
/**
|
||||
* Drops the specified foreign key from a database table.
|
||||
*
|
||||
* @param string $tableName The table to drop the foreign key from
|
||||
* @param string[] $columns Column(s)
|
||||
* @param string|null $constraint Constraint name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropForeignKey($tableName, $columns, $constraint = null);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,128 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use Phinx\Db\Action\AddColumn;
|
||||
use Phinx\Db\Action\AddForeignKey;
|
||||
use Phinx\Db\Action\AddIndex;
|
||||
use Phinx\Db\Action\CreateTable;
|
||||
use Phinx\Db\Action\DropForeignKey;
|
||||
use Phinx\Db\Action\DropIndex;
|
||||
use Phinx\Db\Action\DropTable;
|
||||
use Phinx\Db\Action\RemoveColumn;
|
||||
use Phinx\Db\Action\RenameColumn;
|
||||
use Phinx\Db\Action\RenameTable;
|
||||
use Phinx\Db\Plan\Intent;
|
||||
use Phinx\Db\Plan\Plan;
|
||||
use Phinx\Db\Table\Table;
|
||||
use Phinx\Migration\IrreversibleMigrationException;
|
||||
|
||||
/**
|
||||
* Phinx Proxy Adapter.
|
||||
*
|
||||
* Used for recording migration commands to automatically reverse them.
|
||||
*
|
||||
* @author Rob Morgan <robbym@gmail.com>
|
||||
*/
|
||||
class ProxyAdapter extends AdapterWrapper
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $commands = [];
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAdapterType()
|
||||
{
|
||||
return 'ProxyAdapter';
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createTable(Table $table, array $columns = [], array $indexes = [])
|
||||
{
|
||||
$this->commands[] = new CreateTable($table);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeActions(Table $table, array $actions)
|
||||
{
|
||||
$this->commands = array_merge($this->commands, $actions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of the recorded commands in reverse.
|
||||
*
|
||||
* @throws \Phinx\Migration\IrreversibleMigrationException if a command cannot be reversed.
|
||||
*
|
||||
* @return \Phinx\Db\Plan\Intent
|
||||
*/
|
||||
public function getInvertedCommands()
|
||||
{
|
||||
$inverted = new Intent();
|
||||
|
||||
foreach (array_reverse($this->commands) as $com) {
|
||||
switch (true) {
|
||||
case $com instanceof CreateTable:
|
||||
$inverted->addAction(new DropTable($com->getTable()));
|
||||
break;
|
||||
|
||||
case $com instanceof RenameTable:
|
||||
$inverted->addAction(new RenameTable(new Table($com->getNewName()), $com->getTable()->getName()));
|
||||
break;
|
||||
|
||||
case $com instanceof AddColumn:
|
||||
$inverted->addAction(new RemoveColumn($com->getTable(), $com->getColumn()));
|
||||
break;
|
||||
|
||||
case $com instanceof RenameColumn:
|
||||
$column = clone $com->getColumn();
|
||||
$name = $column->getName();
|
||||
$column->setName($com->getNewName());
|
||||
$inverted->addAction(new RenameColumn($com->getTable(), $column, $name));
|
||||
break;
|
||||
|
||||
case $com instanceof AddIndex:
|
||||
$inverted->addAction(new DropIndex($com->getTable(), $com->getIndex()));
|
||||
break;
|
||||
|
||||
case $com instanceof AddForeignKey:
|
||||
$inverted->addAction(new DropForeignKey($com->getTable(), $com->getForeignKey()));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new IrreversibleMigrationException(sprintf(
|
||||
'Cannot reverse a "%s" command',
|
||||
get_class($com)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
return $inverted;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the recorded commands in reverse.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeInvertedCommands()
|
||||
{
|
||||
$plan = new Plan($this->getInvertedCommands());
|
||||
$plan->executeInverse($this->getAdapter());
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,505 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use BadMethodCallException;
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Db\Action\AddColumn;
|
||||
use Phinx\Db\Action\AddForeignKey;
|
||||
use Phinx\Db\Action\AddIndex;
|
||||
use Phinx\Db\Action\ChangeColumn;
|
||||
use Phinx\Db\Action\ChangeComment;
|
||||
use Phinx\Db\Action\ChangePrimaryKey;
|
||||
use Phinx\Db\Action\DropForeignKey;
|
||||
use Phinx\Db\Action\DropIndex;
|
||||
use Phinx\Db\Action\DropTable;
|
||||
use Phinx\Db\Action\RemoveColumn;
|
||||
use Phinx\Db\Action\RenameColumn;
|
||||
use Phinx\Db\Action\RenameTable;
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\ForeignKey;
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
/**
|
||||
* Table prefix/suffix adapter.
|
||||
*
|
||||
* Used for inserting a prefix or suffix into table names.
|
||||
*
|
||||
* @author Samuel Fisher <sam@sfisher.co>
|
||||
*/
|
||||
class TablePrefixAdapter extends AdapterWrapper implements DirectActionInterface
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAdapterType()
|
||||
{
|
||||
return 'TablePrefixAdapter';
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasTable($tableName)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
|
||||
return parent::hasTable($adapterTableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createTable(Table $table, array $columns = [], array $indexes = [])
|
||||
{
|
||||
$adapterTable = new Table(
|
||||
$this->getAdapterTableName($table->getName()),
|
||||
$table->getOptions()
|
||||
);
|
||||
parent::createTable($adapterTable, $columns, $indexes);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changePrimaryKey(Table $table, $newColumns)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
|
||||
$adapterTable = new Table(
|
||||
$this->getAdapterTableName($table->getName()),
|
||||
$table->getOptions()
|
||||
);
|
||||
$adapter->changePrimaryKey($adapterTable, $newColumns);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeComment(Table $table, $newComment)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
|
||||
$adapterTable = new Table(
|
||||
$this->getAdapterTableName($table->getName()),
|
||||
$table->getOptions()
|
||||
);
|
||||
$adapter->changeComment($adapterTable, $newComment);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renameTable($tableName, $newTableName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapterNewTableName = $this->getAdapterTableName($newTableName);
|
||||
$adapter->renameTable($adapterTableName, $adapterNewTableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropTable($tableName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->dropTable($adapterTableName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addColumn(Table $table, Column $column)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($table->getName());
|
||||
$adapterTable = new Table($adapterTableName, $table->getOptions());
|
||||
$adapter->addColumn($adapterTable, $column);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renameColumn($tableName, $columnName, $newColumnName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->renameColumn($adapterTableName, $columnName, $newColumnName);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeColumn($tableName, $columnName, Column $newColumn)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->changeColumn($adapterTableName, $columnName, $newColumn);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropColumn($tableName, $columnName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->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}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addIndex(Table $table, Index $index)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTable = new Table($table->getName(), $table->getOptions());
|
||||
$adapter->addIndex($adapterTable, $index);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropIndex($tableName, $columns)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->dropIndex($adapterTableName, $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropIndexByName($tableName, $indexName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->dropIndexByName($adapterTableName, $indexName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasPrimaryKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
|
||||
return parent::hasPrimaryKey($adapterTableName, $columns, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function hasForeignKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
|
||||
return parent::hasForeignKey($adapterTableName, $columns, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addForeignKey(Table $table, ForeignKey $foreignKey)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($table->getName());
|
||||
$adapterTable = new Table($adapterTableName, $table->getOptions());
|
||||
$adapter->addForeignKey($adapterTable, $foreignKey);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropForeignKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The underlying adapter does not implement DirectActionInterface');
|
||||
}
|
||||
$adapterTableName = $this->getAdapterTableName($tableName);
|
||||
$adapter->dropForeignKey($adapterTableName, $columns, $constraint);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function insert(Table $table, $row)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($table->getName());
|
||||
$adapterTable = new Table($adapterTableName, $table->getOptions());
|
||||
parent::insert($adapterTable, $row);
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function bulkinsert(Table $table, $rows)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($table->getName());
|
||||
$adapterTable = new Table($adapterTableName, $table->getOptions());
|
||||
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();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeActions(Table $table, array $actions)
|
||||
{
|
||||
$adapterTableName = $this->getAdapterTableName($table->getName());
|
||||
$adapterTable = new Table($adapterTableName, $table->getOptions());
|
||||
|
||||
foreach ($actions as $k => $action) {
|
||||
switch (true) {
|
||||
case ($action instanceof AddColumn):
|
||||
$actions[$k] = new AddColumn($adapterTable, $action->getColumn());
|
||||
break;
|
||||
|
||||
case ($action instanceof AddIndex):
|
||||
$actions[$k] = new AddIndex($adapterTable, $action->getIndex());
|
||||
break;
|
||||
|
||||
case ($action instanceof AddForeignKey):
|
||||
$foreignKey = clone $action->getForeignKey();
|
||||
$refTable = $foreignKey->getReferencedTable();
|
||||
$refTableName = $this->getAdapterTableName($refTable->getName());
|
||||
$foreignKey->setReferencedTable(new Table($refTableName, $refTable->getOptions()));
|
||||
$actions[$k] = new AddForeignKey($adapterTable, $foreignKey);
|
||||
break;
|
||||
|
||||
case ($action instanceof ChangeColumn):
|
||||
$actions[$k] = new ChangeColumn($adapterTable, $action->getColumnName(), $action->getColumn());
|
||||
break;
|
||||
|
||||
case ($action instanceof DropForeignKey):
|
||||
$actions[$k] = new DropForeignKey($adapterTable, $action->getForeignKey());
|
||||
break;
|
||||
|
||||
case ($action instanceof DropIndex):
|
||||
$actions[$k] = new DropIndex($adapterTable, $action->getIndex());
|
||||
break;
|
||||
|
||||
case ($action instanceof DropTable):
|
||||
$actions[$k] = new DropTable($adapterTable);
|
||||
break;
|
||||
|
||||
case ($action instanceof RemoveColumn):
|
||||
$actions[$k] = new RemoveColumn($adapterTable, $action->getColumn());
|
||||
break;
|
||||
|
||||
case ($action instanceof RenameColumn):
|
||||
$actions[$k] = new RenameColumn($adapterTable, $action->getColumn(), $action->getNewName());
|
||||
break;
|
||||
|
||||
case ($action instanceof RenameTable):
|
||||
$actions[$k] = new RenameTable($adapterTable, $action->getNewName());
|
||||
break;
|
||||
|
||||
case ($action instanceof ChangePrimaryKey):
|
||||
$actions[$k] = new ChangePrimaryKey($adapterTable, $action->getNewColumns());
|
||||
break;
|
||||
|
||||
case ($action instanceof ChangeComment):
|
||||
$actions[$k] = new ChangeComment($adapterTable, $action->getNewComment());
|
||||
break;
|
||||
|
||||
default:
|
||||
throw new InvalidArgumentException(
|
||||
sprintf("Forgot to implement table prefixing for action: '%s'", get_class($action))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
parent::executeActions($adapterTable, $actions);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,455 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use BadMethodCallException;
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\ForeignKey;
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Wraps any adapter to record the time spend executing its commands
|
||||
*/
|
||||
class TimedOutputAdapter extends AdapterWrapper implements DirectActionInterface
|
||||
{
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getAdapterType()
|
||||
{
|
||||
return $this->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}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createTable(Table $table, array $columns = [], array $indexes = [])
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('createTable', [$table->getName()]);
|
||||
parent::createTable($table, $columns, $indexes);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changePrimaryKey(Table $table, $newColumns)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('changePrimaryKey', [$table->getName()]);
|
||||
$adapter->changePrimaryKey($table, $newColumns);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeComment(Table $table, $newComment)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('changeComment', [$table->getName()]);
|
||||
$adapter->changeComment($table, $newComment);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renameTable($tableName, $newTableName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('renameTable', [$tableName, $newTableName]);
|
||||
$adapter->renameTable($tableName, $newTableName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropTable($tableName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropTable', [$tableName]);
|
||||
$adapter->dropTable($tableName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function truncateTable($tableName)
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('truncateTable', [$tableName]);
|
||||
parent::truncateTable($tableName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addColumn(Table $table, Column $column)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand(
|
||||
'addColumn',
|
||||
[
|
||||
$table->getName(),
|
||||
$column->getName(),
|
||||
$column->getType(),
|
||||
]
|
||||
);
|
||||
$adapter->addColumn($table, $column);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function renameColumn($tableName, $columnName, $newColumnName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('renameColumn', [$tableName, $columnName, $newColumnName]);
|
||||
$adapter->renameColumn($tableName, $columnName, $newColumnName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function changeColumn($tableName, $columnName, Column $newColumn)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('changeColumn', [$tableName, $columnName, $newColumn->getType()]);
|
||||
$adapter->changeColumn($tableName, $columnName, $newColumn);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropColumn($tableName, $columnName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropColumn', [$tableName, $columnName]);
|
||||
$adapter->dropColumn($tableName, $columnName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addIndex(Table $table, Index $index)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('addIndex', [$table->getName(), $index->getColumns()]);
|
||||
$adapter->addIndex($table, $index);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropIndex($tableName, $columns)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropIndex', [$tableName, $columns]);
|
||||
$adapter->dropIndex($tableName, $columns);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropIndexByName($tableName, $indexName)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropIndexByName', [$tableName, $indexName]);
|
||||
$adapter->dropIndexByName($tableName, $indexName);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addForeignKey(Table $table, ForeignKey $foreignKey)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('addForeignKey', [$table->getName(), $foreignKey->getColumns()]);
|
||||
$adapter->addForeignKey($table, $foreignKey);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropForeignKey($tableName, $columns, $constraint = null)
|
||||
{
|
||||
$adapter = $this->getAdapter();
|
||||
if (!$adapter instanceof DirectActionInterface) {
|
||||
throw new BadMethodCallException('The adapter needs to implement DirectActionInterface');
|
||||
}
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropForeignKey', [$tableName, $columns]);
|
||||
$adapter->dropForeignKey($tableName, $columns, $constraint);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createDatabase($name, $options = [])
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('createDatabase', [$name]);
|
||||
parent::createDatabase($name, $options);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropDatabase($name)
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropDatabase', [$name]);
|
||||
parent::dropDatabase($name);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function createSchema($name = 'public')
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('createSchema', [$name]);
|
||||
parent::createSchema($name);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropSchema($name)
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand('dropSchema', [$name]);
|
||||
parent::dropSchema($name);
|
||||
$end();
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeActions(Table $table, array $actions)
|
||||
{
|
||||
$end = $this->startCommandTimer();
|
||||
$this->writeCommand(sprintf('Altering table %s', $table->getName()));
|
||||
parent::executeActions($table, $actions);
|
||||
$end();
|
||||
}
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* Exception thrown when a column type doesn't match a Phinx type.
|
||||
*
|
||||
* @author Martijn Gastkemper <martijngastkemper@gmail.com>
|
||||
*/
|
||||
class UnsupportedColumnTypeException extends RuntimeException
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Adapter;
|
||||
|
||||
/**
|
||||
* Wrapper Interface.
|
||||
*
|
||||
* @author Woody Gilk <woody.gilk@gmail.com>
|
||||
*/
|
||||
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();
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Plan;
|
||||
|
||||
use Phinx\Db\Action\Action;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
/**
|
||||
* A collection of ALTER actions for a single table
|
||||
*/
|
||||
class AlterTable
|
||||
{
|
||||
/**
|
||||
* The table
|
||||
*
|
||||
* @var \Phinx\Db\Table\Table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* The list of actions to execute
|
||||
*
|
||||
* @var \Phinx\Db\Action\Action[]
|
||||
*/
|
||||
protected $actions = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to change
|
||||
*/
|
||||
public function __construct(Table $table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another action to the collection
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action $action The action to add
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAction(Action $action)
|
||||
{
|
||||
$this->actions[] = $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table associated to this collection
|
||||
*
|
||||
* @return \Phinx\Db\Table\Table
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array with all collected actions
|
||||
*
|
||||
* @return \Phinx\Db\Action\Action[]
|
||||
*/
|
||||
public function getActions()
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Plan;
|
||||
|
||||
use Phinx\Db\Action\Action;
|
||||
|
||||
/**
|
||||
* An intent is a collection of actions for many tables
|
||||
*/
|
||||
class Intent
|
||||
{
|
||||
/**
|
||||
* List of actions to be executed
|
||||
*
|
||||
* @var \Phinx\Db\Action\Action[]
|
||||
*/
|
||||
protected $actions = [];
|
||||
|
||||
/**
|
||||
* Adds a new action to the collection
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action $action The action to add
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAction(Action $action)
|
||||
{
|
||||
$this->actions[] = $action;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the full list of actions
|
||||
*
|
||||
* @return \Phinx\Db\Action\Action[]
|
||||
*/
|
||||
public function getActions()
|
||||
{
|
||||
return $this->actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges another Intent object with this one
|
||||
*
|
||||
* @param \Phinx\Db\Plan\Intent $another The other intent to merge in
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function merge(Intent $another)
|
||||
{
|
||||
$this->actions = array_merge($this->actions, $another->getActions());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Plan;
|
||||
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Index;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
/**
|
||||
* Represents the collection of actions for creating a new table
|
||||
*/
|
||||
class NewTable
|
||||
{
|
||||
/**
|
||||
* The table to create
|
||||
*
|
||||
* @var \Phinx\Db\Table\Table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* The list of columns to add
|
||||
*
|
||||
* @var \Phinx\Db\Table\Column[]
|
||||
*/
|
||||
protected $columns = [];
|
||||
|
||||
/**
|
||||
* The list of indexes to create
|
||||
*
|
||||
* @var \Phinx\Db\Table\Index[]
|
||||
*/
|
||||
protected $indexes = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to create
|
||||
*/
|
||||
public function __construct(Table $table)
|
||||
{
|
||||
$this->table = $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a column to the collection
|
||||
*
|
||||
* @param \Phinx\Db\Table\Column $column The column description
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addColumn(Column $column)
|
||||
{
|
||||
$this->columns[] = $column;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds an index to the collection
|
||||
*
|
||||
* @param \Phinx\Db\Table\Index $index The index description
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addIndex(Index $index)
|
||||
{
|
||||
$this->indexes[] = $index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the table object associated to this collection
|
||||
*
|
||||
* @return \Phinx\Db\Table\Table
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the columns collection
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column[]
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the indexes collection
|
||||
*
|
||||
* @return \Phinx\Db\Table\Index[]
|
||||
*/
|
||||
public function getIndexes()
|
||||
{
|
||||
return $this->indexes;
|
||||
}
|
||||
}
|
||||
+558
@@ -0,0 +1,558 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Plan;
|
||||
|
||||
use ArrayObject;
|
||||
use Phinx\Db\Action\AddColumn;
|
||||
use Phinx\Db\Action\AddForeignKey;
|
||||
use Phinx\Db\Action\AddIndex;
|
||||
use Phinx\Db\Action\ChangeColumn;
|
||||
use Phinx\Db\Action\ChangeComment;
|
||||
use Phinx\Db\Action\ChangePrimaryKey;
|
||||
use Phinx\Db\Action\CreateTable;
|
||||
use Phinx\Db\Action\DropForeignKey;
|
||||
use Phinx\Db\Action\DropIndex;
|
||||
use Phinx\Db\Action\DropTable;
|
||||
use Phinx\Db\Action\RemoveColumn;
|
||||
use Phinx\Db\Action\RenameColumn;
|
||||
use Phinx\Db\Action\RenameTable;
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use Phinx\Db\Plan\Solver\ActionSplitter;
|
||||
use Phinx\Db\Table\Table;
|
||||
|
||||
/**
|
||||
* A Plan takes an Intent and transforms int into a sequence of
|
||||
* instructions that can be correctly executed by an AdapterInterface.
|
||||
*
|
||||
* The main focus of Plan is to arrange the actions in the most efficient
|
||||
* way possible for the database.
|
||||
*/
|
||||
class Plan
|
||||
{
|
||||
/**
|
||||
* List of tables to be created
|
||||
*
|
||||
* @var \Phinx\Db\Plan\NewTable[]
|
||||
*/
|
||||
protected $tableCreates = [];
|
||||
|
||||
/**
|
||||
* List of table updates
|
||||
*
|
||||
* @var \Phinx\Db\Plan\AlterTable[]
|
||||
*/
|
||||
protected $tableUpdates = [];
|
||||
|
||||
/**
|
||||
* List of table removals or renames
|
||||
*
|
||||
* @var \Phinx\Db\Plan\AlterTable[]
|
||||
*/
|
||||
protected $tableMoves = [];
|
||||
|
||||
/**
|
||||
* List of index additions or removals
|
||||
*
|
||||
* @var \Phinx\Db\Plan\AlterTable[]
|
||||
*/
|
||||
protected $indexes = [];
|
||||
|
||||
/**
|
||||
* List of constraint additions or removals
|
||||
*
|
||||
* @var \Phinx\Db\Plan\AlterTable[]
|
||||
*/
|
||||
protected $constraints = [];
|
||||
|
||||
/**
|
||||
* List of dropped columns
|
||||
*
|
||||
* @var \Phinx\Db\Plan\AlterTable[]
|
||||
*/
|
||||
protected $columnRemoves = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Phinx\Db\Plan\Intent $intent All the actions that should be executed
|
||||
*/
|
||||
public function __construct(Intent $intent)
|
||||
{
|
||||
$this->createPlan($intent->getActions());
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the given Intent and creates the separate steps to execute
|
||||
*
|
||||
* @param \Phinx\Db\Plan\Intent $actions The actions to use for the plan
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function createPlan($actions)
|
||||
{
|
||||
$this->gatherCreates($actions);
|
||||
$this->gatherUpdates($actions);
|
||||
$this->gatherTableMoves($actions);
|
||||
$this->gatherIndexes($actions);
|
||||
$this->gatherConstraints($actions);
|
||||
$this->resolveConflicts();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nested list of all the steps to execute
|
||||
*
|
||||
* @return \Phinx\Db\Plan\AlterTable[][]
|
||||
*/
|
||||
protected function updatesSequence()
|
||||
{
|
||||
return [
|
||||
$this->tableUpdates,
|
||||
$this->constraints,
|
||||
$this->indexes,
|
||||
$this->columnRemoves,
|
||||
$this->tableMoves,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a nested list of all the steps to execute in inverse order
|
||||
*
|
||||
* @return \Phinx\Db\Plan\AlterTable[][]
|
||||
*/
|
||||
protected function inverseUpdatesSequence()
|
||||
{
|
||||
return [
|
||||
$this->constraints,
|
||||
$this->tableMoves,
|
||||
$this->indexes,
|
||||
$this->columnRemoves,
|
||||
$this->tableUpdates,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes this plan using the given AdapterInterface
|
||||
*
|
||||
* @param \Phinx\Db\Adapter\AdapterInterface $executor The executor object for the plan
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute(AdapterInterface $executor)
|
||||
{
|
||||
foreach ($this->tableCreates as $newTable) {
|
||||
$executor->createTable($newTable->getTable(), $newTable->getColumns(), $newTable->getIndexes());
|
||||
}
|
||||
|
||||
collection($this->updatesSequence())
|
||||
->unfold()
|
||||
->each(function ($updates) use ($executor) {
|
||||
$executor->executeActions($updates->getTable(), $updates->getActions());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the inverse plan (rollback the actions) with the given AdapterInterface:w
|
||||
*
|
||||
* @param \Phinx\Db\Adapter\AdapterInterface $executor The executor object for the plan
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function executeInverse(AdapterInterface $executor)
|
||||
{
|
||||
collection($this->inverseUpdatesSequence())
|
||||
->unfold()
|
||||
->each(function ($updates) use ($executor) {
|
||||
$executor->executeActions($updates->getTable(), $updates->getActions());
|
||||
});
|
||||
|
||||
foreach ($this->tableCreates as $newTable) {
|
||||
$executor->createTable($newTable->getTable(), $newTable->getColumns(), $newTable->getIndexes());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes certain actions from the plan if they are found to be conflicting or redundant.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function resolveConflicts()
|
||||
{
|
||||
$moveActions = collection($this->tableMoves)
|
||||
->unfold(function ($move) {
|
||||
return $move->getActions();
|
||||
});
|
||||
|
||||
foreach ($moveActions as $action) {
|
||||
if ($action instanceof DropTable) {
|
||||
$this->tableUpdates = $this->forgetTable($action->getTable(), $this->tableUpdates);
|
||||
$this->constraints = $this->forgetTable($action->getTable(), $this->constraints);
|
||||
$this->indexes = $this->forgetTable($action->getTable(), $this->indexes);
|
||||
$this->columnRemoves = $this->forgetTable($action->getTable(), $this->columnRemoves);
|
||||
}
|
||||
}
|
||||
|
||||
// Columns that are dropped will automatically cause the indexes to be dropped as well
|
||||
foreach ($this->columnRemoves as $columnRemove) {
|
||||
foreach ($columnRemove->getActions() as $action) {
|
||||
if ($action instanceof RemoveColumn) {
|
||||
list($this->indexes) = $this->forgetDropIndex(
|
||||
$action->getTable(),
|
||||
[$action->getColumn()->getName()],
|
||||
$this->indexes
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->tableUpdates = collection($this->tableUpdates)
|
||||
// Renaming a column and then changing the renamed column is something people do,
|
||||
// but it is a conflicting action. Luckily solving the conflict can be done by moving
|
||||
// the ChangeColumn action to another AlterTable
|
||||
->unfold(new ActionSplitter(RenameColumn::class, ChangeColumn::class, function (RenameColumn $a, ChangeColumn $b) {
|
||||
return $a->getNewName() == $b->getColumnName();
|
||||
}))
|
||||
->toList();
|
||||
|
||||
$this->constraints = collection($this->constraints)
|
||||
->map(function (AlterTable $alter) {
|
||||
// Dropping indexes used by foreign keys is a conflict, but one we can resolve
|
||||
// if the foreign key is also scheduled to be dropped. If we can find such a a case,
|
||||
// we force the execution of the index drop after the foreign key is dropped.
|
||||
return $this->remapContraintAndIndexConflicts($alter);
|
||||
})
|
||||
// Changing constraint properties sometimes require dropping it and then
|
||||
// creating it again with the new stuff. Unfortunately, we have already bundled
|
||||
// everything together in as few AlterTable statements as we could, so we need to
|
||||
// resolve this conflict manually
|
||||
->unfold(new ActionSplitter(DropForeignKey::class, AddForeignKey::class, function (DropForeignKey $a, AddForeignKey $b) {
|
||||
return $a->getForeignKey()->getColumns() === $b->getForeignKey()->getColumns();
|
||||
}))
|
||||
->toList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all actions related to the given table and keeps the
|
||||
* rest
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to find in the list of actions
|
||||
* @param \Phinx\Db\Plan\AlterTable[] $actions The actions to transform
|
||||
*
|
||||
* @return \Phinx\Db\Plan\AlterTable[] The list of actions without actions for the given table
|
||||
*/
|
||||
protected function forgetTable(Table $table, $actions)
|
||||
{
|
||||
$result = [];
|
||||
foreach ($actions as $action) {
|
||||
if ($action->getTable()->getName() === $table->getName()) {
|
||||
continue;
|
||||
}
|
||||
$result[] = $action;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all DropForeignKey actions in an AlterTable and moves
|
||||
* all conflicting DropIndex action in `$this->indexes` into the
|
||||
* given AlterTable.
|
||||
*
|
||||
* @param \Phinx\Db\Plan\AlterTable $alter The collection of actions to inspect
|
||||
*
|
||||
* @return \Phinx\Db\Plan\AlterTable The updated AlterTable object. This function
|
||||
* has the side effect of changing the `$this->indexes` property.
|
||||
*/
|
||||
protected function remapContraintAndIndexConflicts(AlterTable $alter)
|
||||
{
|
||||
$newAlter = new AlterTable($alter->getTable());
|
||||
collection($alter->getActions())
|
||||
->unfold(function ($action) {
|
||||
if (!$action instanceof DropForeignKey) {
|
||||
return [$action];
|
||||
}
|
||||
|
||||
list($this->indexes, $dropIndexActions) = $this->forgetDropIndex(
|
||||
$action->getTable(),
|
||||
$action->getForeignKey()->getColumns(),
|
||||
$this->indexes
|
||||
);
|
||||
|
||||
$return = [$action];
|
||||
if (!empty($dropIndexActions)) {
|
||||
$return = array_merge($return, $dropIndexActions);
|
||||
}
|
||||
|
||||
return $return;
|
||||
})
|
||||
->each(function ($action) use ($newAlter) {
|
||||
$newAlter->addAction($action);
|
||||
});
|
||||
|
||||
return $newAlter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any DropIndex actions for the given table and exact columns
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to find in the list of actions
|
||||
* @param string[] $columns The column names to match
|
||||
* @param \Phinx\Db\Plan\AlterTable[] $actions The actions to transform
|
||||
*
|
||||
* @return array A tuple containing the list of actions without actions for dropping the index
|
||||
* and a list of drop index actions that were removed.
|
||||
*/
|
||||
protected function forgetDropIndex(Table $table, array $columns, array $actions)
|
||||
{
|
||||
$dropIndexActions = new ArrayObject();
|
||||
$indexes = collection($actions)
|
||||
->map(function ($alter) use ($table, $columns, $dropIndexActions) {
|
||||
if ($alter->getTable()->getName() !== $table->getName()) {
|
||||
return $alter;
|
||||
}
|
||||
|
||||
$newAlter = new AlterTable($table);
|
||||
collection($alter->getActions())
|
||||
->map(function ($action) use ($columns) {
|
||||
if (!$action instanceof DropIndex) {
|
||||
return [$action, null];
|
||||
}
|
||||
if ($action->getIndex()->getColumns() === $columns) {
|
||||
return [null, $action];
|
||||
}
|
||||
|
||||
return [$action, null];
|
||||
})
|
||||
->each(function ($tuple) use ($newAlter, $dropIndexActions) {
|
||||
list($action, $dropIndex) = $tuple;
|
||||
if ($action) {
|
||||
$newAlter->addAction($action);
|
||||
}
|
||||
if ($dropIndex) {
|
||||
$dropIndexActions->append($dropIndex);
|
||||
}
|
||||
});
|
||||
|
||||
return $newAlter;
|
||||
})
|
||||
->toArray();
|
||||
|
||||
return [$indexes, $dropIndexActions->getArrayCopy()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes any RemoveColumn actions for the given table and exact columns
|
||||
*
|
||||
* @param \Phinx\Db\Table\Table $table The table to find in the list of actions
|
||||
* @param string[] $columns The column names to match
|
||||
* @param \Phinx\Db\Plan\AlterTable[] $actions The actions to transform
|
||||
*
|
||||
* @return array A tuple containing the list of actions without actions for removing the column
|
||||
* and a list of remove column actions that were removed.
|
||||
*/
|
||||
protected function forgetRemoveColumn(Table $table, array $columns, array $actions)
|
||||
{
|
||||
$removeColumnActions = new ArrayObject();
|
||||
$indexes = collection($actions)
|
||||
->map(function ($alter) use ($table, $columns, $removeColumnActions) {
|
||||
if ($alter->getTable()->getName() !== $table->getName()) {
|
||||
return $alter;
|
||||
}
|
||||
|
||||
$newAlter = new AlterTable($table);
|
||||
collection($alter->getActions())
|
||||
->map(function ($action) use ($columns) {
|
||||
if (!$action instanceof RemoveColumn) {
|
||||
return [$action, null];
|
||||
}
|
||||
if (in_array($action->getColumn(), $columns)) {
|
||||
return [null, $action];
|
||||
}
|
||||
|
||||
return [$action, null];
|
||||
})
|
||||
->each(function ($tuple) use ($newAlter, $removeColumnActions) {
|
||||
list($action, $removeColumn) = $tuple;
|
||||
if ($action) {
|
||||
$newAlter->addAction($action);
|
||||
}
|
||||
if ($removeColumn) {
|
||||
$removeColumnActions->append($removeColumn);
|
||||
}
|
||||
});
|
||||
|
||||
return $newAlter;
|
||||
})
|
||||
->toArray();
|
||||
|
||||
return [$indexes, $removeColumnActions->getArrayCopy()];
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all table creation actions from the given intent
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action[] $actions The actions to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gatherCreates($actions)
|
||||
{
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof CreateTable;
|
||||
})
|
||||
->map(function ($action) {
|
||||
return [$action->getTable()->getName(), new NewTable($action->getTable())];
|
||||
})
|
||||
->each(function ($step) {
|
||||
$this->tableCreates[$step[0]] = $step[1];
|
||||
});
|
||||
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof AddColumn
|
||||
|| $action instanceof AddIndex;
|
||||
})
|
||||
->filter(function ($action) {
|
||||
return isset($this->tableCreates[$action->getTable()->getName()]);
|
||||
})
|
||||
->each(function ($action) {
|
||||
$table = $action->getTable();
|
||||
|
||||
if ($action instanceof AddColumn) {
|
||||
$this->tableCreates[$table->getName()]->addColumn($action->getColumn());
|
||||
}
|
||||
|
||||
if ($action instanceof AddIndex) {
|
||||
$this->tableCreates[$table->getName()]->addIndex($action->getIndex());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all alter table actions from the given intent
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action[] $actions The actions to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gatherUpdates($actions)
|
||||
{
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof AddColumn
|
||||
|| $action instanceof ChangeColumn
|
||||
|| $action instanceof RemoveColumn
|
||||
|| $action instanceof RenameColumn;
|
||||
})
|
||||
// We are only concerned with table changes
|
||||
->reject(function ($action) {
|
||||
return isset($this->tableCreates[$action->getTable()->getName()]);
|
||||
})
|
||||
->each(function ($action) {
|
||||
$table = $action->getTable();
|
||||
$name = $table->getName();
|
||||
|
||||
if ($action instanceof RemoveColumn) {
|
||||
if (!isset($this->columnRemoves[$name])) {
|
||||
$this->columnRemoves[$name] = new AlterTable($table);
|
||||
}
|
||||
$this->columnRemoves[$name]->addAction($action);
|
||||
} else {
|
||||
if (!isset($this->tableUpdates[$name])) {
|
||||
$this->tableUpdates[$name] = new AlterTable($table);
|
||||
}
|
||||
$this->tableUpdates[$name]->addAction($action);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all alter table drop and renames from the given intent
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action[] $actions The actions to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gatherTableMoves($actions)
|
||||
{
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof DropTable
|
||||
|| $action instanceof RenameTable
|
||||
|| $action instanceof ChangePrimaryKey
|
||||
|| $action instanceof ChangeComment;
|
||||
})
|
||||
->each(function ($action) {
|
||||
$table = $action->getTable();
|
||||
$name = $table->getName();
|
||||
|
||||
if (!isset($this->tableMoves[$name])) {
|
||||
$this->tableMoves[$name] = new AlterTable($table);
|
||||
}
|
||||
|
||||
$this->tableMoves[$name]->addAction($action);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all index creation and drops from the given intent
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action[] $actions The actions to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gatherIndexes($actions)
|
||||
{
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof AddIndex
|
||||
|| $action instanceof DropIndex;
|
||||
})
|
||||
->reject(function ($action) {
|
||||
// Indexes for new tables are created inline
|
||||
// so we don't wan't them here too
|
||||
return isset($this->tableCreates[$action->getTable()->getName()]);
|
||||
})
|
||||
->each(function ($action) {
|
||||
$table = $action->getTable();
|
||||
$name = $table->getName();
|
||||
|
||||
if (!isset($this->indexes[$name])) {
|
||||
$this->indexes[$name] = new AlterTable($table);
|
||||
}
|
||||
|
||||
$this->indexes[$name]->addAction($action);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Collects all foreign key creation and drops from the given intent
|
||||
*
|
||||
* @param \Phinx\Db\Action\Action[] $actions The actions to parse
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function gatherConstraints($actions)
|
||||
{
|
||||
collection($actions)
|
||||
->filter(function ($action) {
|
||||
return $action instanceof AddForeignKey
|
||||
|| $action instanceof DropForeignKey;
|
||||
})
|
||||
->each(function ($action) {
|
||||
$table = $action->getTable();
|
||||
$name = $table->getName();
|
||||
|
||||
if (!isset($this->constraints[$name])) {
|
||||
$this->constraints[$name] = new AlterTable($table);
|
||||
}
|
||||
|
||||
$this->constraints[$name]->addAction($action);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,116 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Plan\Solver;
|
||||
|
||||
use Phinx\Db\Plan\AlterTable;
|
||||
|
||||
/**
|
||||
* A Plan takes an Intent and transforms int into a sequence of
|
||||
* instructions that can be correctly executed by an AdapterInterface.
|
||||
*
|
||||
* The main focus of Plan is to arrange the actions in the most efficient
|
||||
* way possible for the database.
|
||||
*/
|
||||
class ActionSplitter
|
||||
{
|
||||
/**
|
||||
* The fully qualified class name of the Action class to match for conflicts
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $conflictClass;
|
||||
|
||||
/**
|
||||
* The fully qualified class name of the Action class to match for conflicts, which
|
||||
* is the dual of $conflictClass. For example `AddColumn` and `DropColumn` are duals.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
protected $conflictClassDual;
|
||||
|
||||
/**
|
||||
* A callback used to signal the actual presence of a conflict, that will be used to
|
||||
* partition the AlterTable into non-conflicting parts.
|
||||
*
|
||||
* The callback receives as first argument amn instance of $conflictClass and as second
|
||||
* argument an instance of $conflictClassDual
|
||||
*
|
||||
* @var callable
|
||||
*/
|
||||
protected $conflictFilter;
|
||||
|
||||
/**
|
||||
* Comstructor
|
||||
*
|
||||
* @param string $conflictClass The fully qualified class name of the Action class to match for conflicts
|
||||
* @param string $conflictClassDual The fully qualified class name of the Action class to match for conflicts,
|
||||
* which is the dual of $conflictClass. For example `AddColumn` and `DropColumn` are duals.
|
||||
* @param callable $conflictFilter The collection of actions to inspect
|
||||
*/
|
||||
public function __construct($conflictClass, $conflictClassDual, callable $conflictFilter)
|
||||
{
|
||||
$this->conflictClass = $conflictClass;
|
||||
$this->conflictClassDual = $conflictClassDual;
|
||||
$this->conflictFilter = $conflictFilter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returs a sequence of AlterTable instructions that are non conflicting
|
||||
* based on the constructor parameters.
|
||||
*
|
||||
* @param \Phinx\Db\Plan\AlterTable $alter The collection of actions to inspect
|
||||
*
|
||||
* @return \Phinx\Db\Plan\AlterTable[] A list of AlterTable that can be executed without
|
||||
* this type of conflict
|
||||
*/
|
||||
public function __invoke(AlterTable $alter)
|
||||
{
|
||||
$actions = collection($alter->getActions());
|
||||
$conflictActions = $actions
|
||||
->filter(function ($action) {
|
||||
return $action instanceof $this->conflictClass;
|
||||
})
|
||||
->toList();
|
||||
|
||||
$originalAlter = new AlterTable($alter->getTable());
|
||||
$newAlter = new AlterTable($alter->getTable());
|
||||
|
||||
$actions
|
||||
->map(function ($action) use ($conflictActions) {
|
||||
if (!$action instanceof $this->conflictClassDual) {
|
||||
return [$action, null];
|
||||
}
|
||||
|
||||
$found = false;
|
||||
$matches = $this->conflictFilter;
|
||||
foreach ($conflictActions as $ca) {
|
||||
if ($matches($ca, $action)) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($found) {
|
||||
return [null, $action];
|
||||
}
|
||||
|
||||
return [$action, null];
|
||||
})
|
||||
->each(function ($pair) use ($originalAlter, $newAlter) {
|
||||
list($original, $new) = $pair;
|
||||
if ($original) {
|
||||
$originalAlter->addAction($original);
|
||||
}
|
||||
if ($new) {
|
||||
$newAlter->addAction($new);
|
||||
}
|
||||
});
|
||||
|
||||
return [$originalAlter, $newAlter];
|
||||
}
|
||||
}
|
||||
+724
@@ -0,0 +1,724 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Phinx\Db\Action\AddColumn;
|
||||
use Phinx\Db\Action\AddForeignKey;
|
||||
use Phinx\Db\Action\AddIndex;
|
||||
use Phinx\Db\Action\ChangeColumn;
|
||||
use Phinx\Db\Action\ChangeComment;
|
||||
use Phinx\Db\Action\ChangePrimaryKey;
|
||||
use Phinx\Db\Action\CreateTable;
|
||||
use Phinx\Db\Action\DropForeignKey;
|
||||
use Phinx\Db\Action\DropIndex;
|
||||
use Phinx\Db\Action\DropTable;
|
||||
use Phinx\Db\Action\RemoveColumn;
|
||||
use Phinx\Db\Action\RenameColumn;
|
||||
use Phinx\Db\Action\RenameTable;
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use Phinx\Db\Plan\Intent;
|
||||
use Phinx\Db\Plan\Plan;
|
||||
use Phinx\Db\Table\Column;
|
||||
use Phinx\Db\Table\Table as TableValue;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* This object is based loosely on: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html.
|
||||
*/
|
||||
class Table
|
||||
{
|
||||
/**
|
||||
* @var \Phinx\Db\Table\Table
|
||||
*/
|
||||
protected $table;
|
||||
|
||||
/**
|
||||
* @var \Phinx\Db\Adapter\AdapterInterface
|
||||
*/
|
||||
protected $adapter;
|
||||
|
||||
/**
|
||||
* @var \Phinx\Db\Plan\Intent
|
||||
*/
|
||||
protected $actions;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $data = [];
|
||||
|
||||
/**
|
||||
* @param string $name Table Name
|
||||
* @param array $options Options
|
||||
* @param \Phinx\Db\Adapter\AdapterInterface|null $adapter Database Adapter
|
||||
*/
|
||||
public function __construct($name, $options = [], AdapterInterface $adapter = null)
|
||||
{
|
||||
$this->table = new TableValue($name, $options);
|
||||
$this->actions = new Intent();
|
||||
|
||||
if ($adapter !== null) {
|
||||
$this->setAdapter($adapter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->table->getName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->table->getOptions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table name and options as an object
|
||||
*
|
||||
* @return \Phinx\Db\Table\Table
|
||||
*/
|
||||
public function getTable()
|
||||
{
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the database adapter.
|
||||
*
|
||||
* @param \Phinx\Db\Adapter\AdapterInterface $adapter Database Adapter
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setAdapter(AdapterInterface $adapter)
|
||||
{
|
||||
$this->adapter = $adapter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the database adapter.
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return \Phinx\Db\Adapter\AdapterInterface|null
|
||||
*/
|
||||
public function getAdapter()
|
||||
{
|
||||
if (!$this->adapter) {
|
||||
throw new RuntimeException('There is no database adapter set yet, cannot proceed');
|
||||
}
|
||||
|
||||
return $this->adapter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the table have pending actions?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasPendingActions()
|
||||
{
|
||||
return count($this->actions->getActions()) > 0 || count($this->data) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the table exist?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function exists()
|
||||
{
|
||||
return $this->getAdapter()->hasTable($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Drops the database table.
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function drop()
|
||||
{
|
||||
$this->actions->addAction(new DropTable($this->table));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renames the database table.
|
||||
*
|
||||
* @param string $newTableName New Table Name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function rename($newTableName)
|
||||
{
|
||||
$this->actions->addAction(new RenameTable($this->table, $newTableName));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the primary key of the database table.
|
||||
*
|
||||
* @param string|array|null $columns Column name(s) to belong to the primary key, or null to drop the key
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function changePrimaryKey($columns)
|
||||
{
|
||||
$this->actions->addAction(new ChangePrimaryKey($this->table, $columns));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the comment of the database table.
|
||||
*
|
||||
* @param string|null $comment New comment string, or null to drop the comment
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function changeComment($comment)
|
||||
{
|
||||
$this->actions->addAction(new ChangeComment($this->table, $comment));
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of the table columns.
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column[]
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->getAdapter()->getColumns($this->getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a table column if it exists.
|
||||
*
|
||||
* @param string $name Column name
|
||||
*
|
||||
* @return \Phinx\Db\Table\Column|null
|
||||
*/
|
||||
public function getColumn($name)
|
||||
{
|
||||
$columns = array_filter(
|
||||
$this->getColumns(),
|
||||
function ($column) use ($name) {
|
||||
return $column->getName() === $name;
|
||||
}
|
||||
);
|
||||
|
||||
return array_pop($columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets an array of data to be inserted.
|
||||
*
|
||||
* @param array $data Data
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 data to be inserted
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function resetData()
|
||||
{
|
||||
$this->setData([]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets all of the pending table changes.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function reset()
|
||||
{
|
||||
$this->actions = new Intent();
|
||||
$this->resetData();
|
||||
}
|
||||
|
||||
/**
|
||||
* 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|\Phinx\Util\Literal|null $type Column Type
|
||||
* @param array $options Column Options
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addColumn($columnName, $type = null, $options = [])
|
||||
{
|
||||
if ($columnName instanceof Column) {
|
||||
$action = new AddColumn($this->table, $columnName);
|
||||
} else {
|
||||
$action = AddColumn::build($this->table, $columnName, $type, $options);
|
||||
}
|
||||
|
||||
// Delegate to Adapters to check column type
|
||||
if (!$this->getAdapter()->isValidColumnType($action->getColumn())) {
|
||||
throw new InvalidArgumentException(sprintf(
|
||||
'An invalid column type "%s" was specified for column "%s".',
|
||||
$type,
|
||||
$action->getColumn()->getName()
|
||||
));
|
||||
}
|
||||
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a table column.
|
||||
*
|
||||
* @param string $columnName Column Name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeColumn($columnName)
|
||||
{
|
||||
$action = RemoveColumn::build($this->table, $columnName);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Rename a table column.
|
||||
*
|
||||
* @param string $oldName Old Column Name
|
||||
* @param string $newName New Column Name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function renameColumn($oldName, $newName)
|
||||
{
|
||||
$action = RenameColumn::build($this->table, $oldName, $newName);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Change a table column type.
|
||||
*
|
||||
* @param string $columnName Column Name
|
||||
* @param string|\Phinx\Db\Table\Column|\Phinx\Util\Literal $newColumnType New Column Type
|
||||
* @param array $options Options
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function changeColumn($columnName, $newColumnType, array $options = [])
|
||||
{
|
||||
if ($newColumnType instanceof Column) {
|
||||
$action = new ChangeColumn($this->table, $columnName, $newColumnType);
|
||||
} else {
|
||||
$action = ChangeColumn::build($this->table, $columnName, $newColumnType, $options);
|
||||
}
|
||||
$this->actions->addAction($action);
|
||||
|
||||
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 $this
|
||||
*/
|
||||
public function addIndex($columns, array $options = [])
|
||||
{
|
||||
$action = AddIndex::build($this->table, $columns, $options);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given index from a table.
|
||||
*
|
||||
* @param string|array $columns Columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeIndex($columns)
|
||||
{
|
||||
$action = DropIndex::build($this->table, is_string($columns) ? [$columns] : $columns);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given index identified by its name from a table.
|
||||
*
|
||||
* @param string $name Index name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function removeIndexByName($name)
|
||||
{
|
||||
$action = DropIndex::buildFromName($this->table, $name);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an index exists.
|
||||
*
|
||||
* @param string|array $columns Columns
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIndex($columns)
|
||||
{
|
||||
return $this->getAdapter()->hasIndex($this->getName(), $columns);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if an index specified by name exists.
|
||||
*
|
||||
* @param string $indexName
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasIndexByName($indexName)
|
||||
{
|
||||
return $this->getAdapter()->hasIndexByName($this->getName(), $indexName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 $this
|
||||
*/
|
||||
public function addForeignKey($columns, $referencedTable, $referencedColumns = ['id'], $options = [])
|
||||
{
|
||||
$action = AddForeignKey::build($this->table, $columns, $referencedTable, $referencedColumns, $options);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a foreign key to a database table with a given name.
|
||||
*
|
||||
* In $options you can specify on_delete|on_delete = cascade|no_action ..,
|
||||
* on_update, constraint = constraint name.
|
||||
*
|
||||
* @param string $name The 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 $this
|
||||
*/
|
||||
public function addForeignKeyWithName($name, $columns, $referencedTable, $referencedColumns = ['id'], $options = [])
|
||||
{
|
||||
$action = AddForeignKey::build(
|
||||
$this->table,
|
||||
$columns,
|
||||
$referencedTable,
|
||||
$referencedColumns,
|
||||
$options,
|
||||
$name
|
||||
);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the given foreign key from the table.
|
||||
*
|
||||
* @param string|array $columns Column(s)
|
||||
* @param string|null $constraint Constraint names
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function dropForeignKey($columns, $constraint = null)
|
||||
{
|
||||
$action = DropForeignKey::build($this->table, $columns, $constraint);
|
||||
$this->actions->addAction($action);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks to see if a foreign key exists.
|
||||
*
|
||||
* @param string|array $columns Column(s)
|
||||
* @param string|null $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|null $createdAt Alternate name for the created_at column
|
||||
* @param string|null $updatedAt Alternate name for the updated_at column
|
||||
* @param bool $withTimezone Whether to set the timezone option on the added columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTimestamps($createdAt = 'created_at', $updatedAt = 'updated_at', $withTimezone = false)
|
||||
{
|
||||
$createdAt = $createdAt === null ? 'created_at' : $createdAt;
|
||||
$updatedAt = $updatedAt === null ? 'updated_at' : $updatedAt;
|
||||
|
||||
$this->addColumn($createdAt, 'timestamp', [
|
||||
'default' => 'CURRENT_TIMESTAMP',
|
||||
'update' => '',
|
||||
'timezone' => $withTimezone,
|
||||
])
|
||||
->addColumn($updatedAt, 'timestamp', [
|
||||
'null' => true,
|
||||
'default' => null,
|
||||
'timezone' => $withTimezone,
|
||||
]);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Alias that always sets $withTimezone to true
|
||||
*
|
||||
* @see addTimestamps
|
||||
*
|
||||
* @param string|null $createdAt Alternate name for the created_at column
|
||||
* @param string|null $updatedAt Alternate name for the updated_at column
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function addTimestampsWithTimezone($createdAt = null, $updatedAt = null)
|
||||
{
|
||||
$this->addTimestamps($createdAt, $updatedAt, true);
|
||||
|
||||
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 $this
|
||||
*/
|
||||
public function insert($data)
|
||||
{
|
||||
// handle array of array situations
|
||||
$keys = array_keys($data);
|
||||
$firstKey = array_shift($keys);
|
||||
if ($firstKey !== null && is_array($data[$firstKey])) {
|
||||
foreach ($data as $row) {
|
||||
$this->data[] = $row;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
if (count($data) > 0) {
|
||||
$this->data[] = $data;
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a table from the object instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function create()
|
||||
{
|
||||
$this->executeActions(false);
|
||||
$this->saveData();
|
||||
$this->reset(); // reset pending changes
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a table from the object instance.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update()
|
||||
{
|
||||
$this->executeActions(true);
|
||||
$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->table, $this->getData());
|
||||
} else {
|
||||
foreach ($this->getData() as $row) {
|
||||
$this->getAdapter()->insert($this->table, $row);
|
||||
}
|
||||
}
|
||||
|
||||
$this->resetData();
|
||||
}
|
||||
|
||||
/**
|
||||
* Immediately truncates the table. This operation cannot be undone
|
||||
*
|
||||
* @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
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes all the pending actions for this table
|
||||
*
|
||||
* @param bool $exists Whether or not the table existed prior to executing this method
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function executeActions($exists)
|
||||
{
|
||||
// Renaming a table is tricky, specially when running a reversible migration
|
||||
// down. We will just assume the table already exists if the user commands a
|
||||
// table rename.
|
||||
$renamed = collection($this->actions->getActions())
|
||||
->filter(function ($action) {
|
||||
return $action instanceof RenameTable;
|
||||
})
|
||||
->first();
|
||||
|
||||
if ($renamed) {
|
||||
$exists = true;
|
||||
}
|
||||
|
||||
// If the table does not exist, the last command in the chain needs to be
|
||||
// a CreateTable action.
|
||||
if (!$exists) {
|
||||
$this->actions->addAction(new CreateTable($this->table));
|
||||
}
|
||||
|
||||
$plan = new Plan($this->actions);
|
||||
$plan->execute($this->getAdapter());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,761 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Table;
|
||||
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use RuntimeException;
|
||||
use UnexpectedValueException;
|
||||
|
||||
/**
|
||||
* This object is based loosely on: http://api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/Table.html.
|
||||
*/
|
||||
class Column
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string|\Phinx\Util\Literal
|
||||
*/
|
||||
protected $type;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $null = false;
|
||||
|
||||
/**
|
||||
* @var mixed|null
|
||||
*/
|
||||
protected $default;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $identity = false;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $seed;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $increment;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $scale;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $after;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $update;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $comment;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $signed = true;
|
||||
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
protected $timezone = false;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $properties = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $collation;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $encoding;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
protected $srid;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $values;
|
||||
|
||||
/**
|
||||
* Sets the column name.
|
||||
*
|
||||
* @param string $name
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column type.
|
||||
*
|
||||
* @param string|\Phinx\Util\Literal $type Column type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setType($type)
|
||||
{
|
||||
$this->type = $type;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column type.
|
||||
*
|
||||
* @return string|\Phinx\Util\Literal
|
||||
*/
|
||||
public function getType()
|
||||
{
|
||||
return $this->type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column limit.
|
||||
*
|
||||
* @param int $limit
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 number precision for decimal or float column.
|
||||
*
|
||||
* For example `DECIMAL(5,2)`, 5 is the precision and 2 is the scale,
|
||||
* and the column could store value from -999.99 to 999.99.
|
||||
*
|
||||
* @param int $precision Number precision
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPrecision($precision)
|
||||
{
|
||||
$this->setLimit($precision);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number precision for decimal or float column.
|
||||
*
|
||||
* For example `DECIMAL(5,2)`, 5 is the precision and 2 is the scale,
|
||||
* and the column could store value from -999.99 to 999.99.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getPrecision()
|
||||
{
|
||||
return $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column identity seed.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getSeed()
|
||||
{
|
||||
return $this->seed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column identity increment.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getIncrement()
|
||||
{
|
||||
return $this->increment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column identity seed.
|
||||
*
|
||||
* @param int $seed Number seed
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setSeed($seed)
|
||||
{
|
||||
$this->seed = $seed;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column identity increment.
|
||||
*
|
||||
* @param int $increment Number increment
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setIncrement($increment)
|
||||
{
|
||||
$this->increment = $increment;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number scale for decimal or float column.
|
||||
*
|
||||
* For example `DECIMAL(5,2)`, 5 is the precision and 2 is the scale,
|
||||
* and the column could store value from -999.99 to 999.99.
|
||||
*
|
||||
* @param int $scale Number scale
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setScale($scale)
|
||||
{
|
||||
$this->scale = $scale;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the number scale for decimal or float column.
|
||||
*
|
||||
* For example `DECIMAL(5,2)`, 5 is the precision and 2 is the scale,
|
||||
* and the column could store value from -999.99 to 999.99.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function getScale()
|
||||
{
|
||||
return $this->scale;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the number precision and scale for decimal or float column.
|
||||
*
|
||||
* For example `DECIMAL(5,2)`, 5 is the precision and 2 is the scale,
|
||||
* and the column could store value from -999.99 to 999.99.
|
||||
*
|
||||
* @param int $precision Number precision
|
||||
* @param int $scale Number scale
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setPrecisionAndScale($precision, $scale)
|
||||
{
|
||||
$this->setLimit($precision);
|
||||
$this->scale = $scale;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column comment.
|
||||
*
|
||||
* @param string $comment
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
public function setProperties($properties)
|
||||
{
|
||||
$this->properties = $properties;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets field properties
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getProperties()
|
||||
{
|
||||
return $this->properties;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets field values.
|
||||
*
|
||||
* @param array|string $values
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the column SRID.
|
||||
*
|
||||
* @param int $srid SRID
|
||||
* @return \Phinx\Db\Table\Column
|
||||
*/
|
||||
public function setSrid($srid)
|
||||
{
|
||||
$this->srid = $srid;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the column SRID.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getSrid()
|
||||
{
|
||||
return $this->srid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all allowed options. Each option must have a corresponding `setFoo` method.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getValidOptions()
|
||||
{
|
||||
return [
|
||||
'limit',
|
||||
'default',
|
||||
'null',
|
||||
'identity',
|
||||
'scale',
|
||||
'after',
|
||||
'update',
|
||||
'comment',
|
||||
'signed',
|
||||
'timezone',
|
||||
'properties',
|
||||
'values',
|
||||
'collation',
|
||||
'encoding',
|
||||
'srid',
|
||||
'seed',
|
||||
'increment',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all aliased options. Each alias must reference a valid option.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
protected function getAliasedOptions()
|
||||
{
|
||||
return [
|
||||
'length' => 'limit',
|
||||
'precision' => 'limit',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Utility method that maps an array of column options to this objects methods.
|
||||
*
|
||||
* @param array $options Options
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,244 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Table;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use RuntimeException;
|
||||
|
||||
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\Table
|
||||
*/
|
||||
protected $referencedTable;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $referencedColumns = [];
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $onDelete;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $onUpdate;
|
||||
|
||||
/**
|
||||
* @var string|bool
|
||||
*/
|
||||
protected $constraint;
|
||||
|
||||
/**
|
||||
* Sets the foreign key columns.
|
||||
*
|
||||
* @param array|string $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $table The table this KEY is pointing to
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setReferencedTable(Table $table)
|
||||
{
|
||||
$this->referencedTable = $table;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the foreign key referenced table.
|
||||
*
|
||||
* @return \Phinx\Db\Table\Table
|
||||
*/
|
||||
public function getReferencedTable()
|
||||
{
|
||||
return $this->referencedTable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the foreign key referenced columns.
|
||||
*
|
||||
* @param array $referencedColumns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
public function setOnUpdate($onUpdate)
|
||||
{
|
||||
$this->onUpdate = $this->normalizeAction($onUpdate);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets constraint for the foreign key.
|
||||
*
|
||||
* @param string $constraint
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 ($option === 'delete') {
|
||||
$this->setOnDelete($value);
|
||||
} elseif ($option === 'update') {
|
||||
$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);
|
||||
}
|
||||
}
|
||||
+177
@@ -0,0 +1,177 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Table;
|
||||
|
||||
use RuntimeException;
|
||||
|
||||
class Index
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const UNIQUE = 'unique';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const INDEX = 'index';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
const FULLTEXT = 'fulltext';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $columns;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $type = self::INDEX;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var int|array|null
|
||||
*/
|
||||
protected $limit;
|
||||
|
||||
/**
|
||||
* Sets the index columns.
|
||||
*
|
||||
* @param array $columns
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setColumns($columns)
|
||||
{
|
||||
$this->columns = $columns;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index columns.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getColumns()
|
||||
{
|
||||
return $this->columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index type.
|
||||
*
|
||||
* @param string $type
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index name.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the index limit.
|
||||
*
|
||||
* @param int|array $limit limit value or array of limit value
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the index limit.
|
||||
*
|
||||
* @return int|array
|
||||
*/
|
||||
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 $this
|
||||
*/
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Table;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
class Table
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected $options;
|
||||
|
||||
/**
|
||||
* @param string $name The table name
|
||||
* @param array $options The creation options for this table
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct($name, array $options = [])
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new InvalidArgumentException('Cannot use an empty table name');
|
||||
}
|
||||
|
||||
$this->name = $name;
|
||||
$this->options = $options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table name.
|
||||
*
|
||||
* @param string $name The name of the table
|
||||
*
|
||||
* @return $this
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->name = $name;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the table options
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the table options
|
||||
*
|
||||
* @param array $options The options for the table creation
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setOptions(array $options)
|
||||
{
|
||||
$this->options = $options;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,126 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Db\Util;
|
||||
|
||||
/**
|
||||
* Contains all the information for running an ALTER command for a table,
|
||||
* and any post-steps required after the fact.
|
||||
*/
|
||||
class AlterInstructions
|
||||
{
|
||||
/**
|
||||
* @var string[] The SQL snippets to be added to an ALTER instruction
|
||||
*/
|
||||
protected $alterParts = [];
|
||||
|
||||
/**
|
||||
* @var mixed[] The SQL commands to be executed after the ALTER instruction
|
||||
*/
|
||||
protected $postSteps = [];
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param array $alterParts SQL snippets to be added to a single ALTER instruction per table
|
||||
* @param array $postSteps SQL commands to be executed after the ALTER instruction
|
||||
*/
|
||||
public function __construct(array $alterParts = [], array $postSteps = [])
|
||||
{
|
||||
$this->alterParts = $alterParts;
|
||||
$this->postSteps = $postSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds another part to the single ALTER instruction
|
||||
*
|
||||
* @param string $part The SQL snipped to add as part of the ALTER instruction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addAlter($part)
|
||||
{
|
||||
$this->alterParts[] = $part;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a SQL command to be executed after the ALTER instruction.
|
||||
* This method allows a callable, with will get an empty array as state
|
||||
* for the first time and will pass the return value of the callable to
|
||||
* the next callable, if present.
|
||||
*
|
||||
* This allows to keep a single state across callbacks.
|
||||
*
|
||||
* @param string|callable $sql The SQL to run after, or a callable to execute
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function addPostStep($sql)
|
||||
{
|
||||
$this->postSteps[] = $sql;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the alter SQL snippets
|
||||
*
|
||||
* @return string[]
|
||||
*/
|
||||
public function getAlterParts()
|
||||
{
|
||||
return $this->alterParts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the SQL commands to run after the ALTER instruction
|
||||
*
|
||||
* @return mixed[]
|
||||
*/
|
||||
public function getPostSteps()
|
||||
{
|
||||
return $this->postSteps;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges another AlterInstructions object to this one
|
||||
*
|
||||
* @param \Phinx\Db\Util\AlterInstructions $other The other collection of instructions to merge in
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function merge(AlterInstructions $other)
|
||||
{
|
||||
$this->alterParts = array_merge($this->alterParts, $other->getAlterParts());
|
||||
$this->postSteps = array_merge($this->postSteps, $other->getPostSteps());
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the ALTER instruction and all of the post steps.
|
||||
*
|
||||
* @param string $alterTemplate The template for the alter instruction
|
||||
* @param callable $executor The function to be used to execute all instructions
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function execute($alterTemplate, callable $executor)
|
||||
{
|
||||
if ($this->alterParts) {
|
||||
$alter = sprintf($alterTemplate, implode(', ', $this->alterParts));
|
||||
$executor($alter);
|
||||
}
|
||||
|
||||
$state = [];
|
||||
|
||||
foreach ($this->postSteps as $instruction) {
|
||||
if (is_callable($instruction)) {
|
||||
$state = $instruction($state);
|
||||
continue;
|
||||
}
|
||||
|
||||
$executor($instruction);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,350 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Migration;
|
||||
|
||||
use Phinx\Db\Adapter\AdapterInterface;
|
||||
use Phinx\Db\Table;
|
||||
use RuntimeException;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
/**
|
||||
* Abstract Migration Class.
|
||||
*
|
||||
* It is expected that the migrations you write extend from this class.
|
||||
*
|
||||
* This abstract class proxies the various database methods to your specified
|
||||
* adapter.
|
||||
*
|
||||
* @author Rob Morgan <robbym@gmail.com>
|
||||
*/
|
||||
abstract class AbstractMigration implements MigrationInterface
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $environment;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* List of all the table objects created by this migration
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
protected $tables = [];
|
||||
|
||||
/**
|
||||
* @param string $environment Environment Detected
|
||||
* @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($environment, $version, InputInterface $input = null, OutputInterface $output = null)
|
||||
{
|
||||
$this->environment = $environment;
|
||||
$this->version = $version;
|
||||
|
||||
if ($input !== null) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
|
||||
if ($output !== null) {
|
||||
$this->setOutput($output);
|
||||
}
|
||||
|
||||
$this->init();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize method.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
protected function init()
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 static::class;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function getEnvironment()
|
||||
{
|
||||
return $this->environment;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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 getQueryBuilder()
|
||||
{
|
||||
return $this->getAdapter()->getQueryBuilder();
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
trigger_error('insert() is deprecated since 0.10.0. Use $this->table($tableName)->insert($data)->save() instead.', E_USER_DEPRECATED);
|
||||
// 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 = [])
|
||||
{
|
||||
$table = new Table($tableName, $options, $this->getAdapter());
|
||||
$this->tables[] = $table;
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* A short-hand method to drop the given database table.
|
||||
*
|
||||
* @deprecated since 0.10.0. Use $this->table($tableName)->drop()->save() instead.
|
||||
*
|
||||
* @param string $tableName Table Name
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function dropTable($tableName)
|
||||
{
|
||||
trigger_error('dropTable() is deprecated since 0.10.0. Use $this->table($tableName)->drop()->save() instead.', E_USER_DEPRECATED);
|
||||
$this->table($tableName)->drop()->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform checks on the migration, print a warning
|
||||
* if there are potential problems.
|
||||
*
|
||||
* Right now, the only check is if there is both a `change()` and
|
||||
* an `up()` or a `down()` method.
|
||||
*
|
||||
* @param string|null $direction
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function preFlightCheck($direction = null)
|
||||
{
|
||||
if (method_exists($this, MigrationInterface::CHANGE)) {
|
||||
if (method_exists($this, MigrationInterface::UP) ||
|
||||
method_exists($this, MigrationInterface::DOWN)
|
||||
) {
|
||||
$this->output->writeln(sprintf(
|
||||
'<comment>warning</comment> Migration contains both change() and/or up()/down() methods. <options=bold>Ignoring up() and down()</>.'
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform checks on the migration after completion
|
||||
*
|
||||
* Right now, the only check is whether all changes were committed
|
||||
*
|
||||
* @param string|null $direction direction of migration
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function postFlightCheck($direction = null)
|
||||
{
|
||||
foreach ($this->tables as $table) {
|
||||
if ($table->hasPendingActions()) {
|
||||
throw new RuntimeException('Migration has pending actions after execution!');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* MIT License
|
||||
* For full license information, please view the LICENSE file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Phinx\Migration;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
abstract class AbstractTemplateCreation implements CreationInterface
|
||||
{
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Input\InputInterface
|
||||
*/
|
||||
protected $input;
|
||||
|
||||
/**
|
||||
* @var \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected $output;
|
||||
|
||||
/**
|
||||
* @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)
|
||||
{
|
||||
if ($input !== null) {
|
||||
$this->setInput($input);
|
||||
}
|
||||
if ($output !== null) {
|
||||
$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;
|
||||
}
|
||||
}
|
||||
Loaded 100 of 6566 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user