diff --git a/.github/dependabot.yml b/.github/dependabot.yml index c630ffa6b..6647c4286 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,5 +3,10 @@ updates: - package-ecosystem: composer directory: "/" schedule: - interval: daily + interval: weekly + open-pull-requests-limit: 10 +- package-ecosystem: github-actions + directory: "/" + schedule: + interval: weekly open-pull-requests-limit: 10 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 783b2b338..15038f19d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,6 +1,12 @@ name: CI -on: ['push', 'pull_request'] +on: + push: + branches: + - '0.x' + - '0.next' + - '1.x' + pull_request: jobs: testsuite: @@ -8,13 +14,15 @@ jobs: strategy: fail-fast: false matrix: - php-version: ['7.2', '8.0', '8.1'] + php-version: ['7.2', '7.4', '8.0', '8.1'] db-type: [sqlite, mysql, pgsql] prefer-lowest: [''] include: + - php-version: '8.2' + db-type: mysql - php-version: '7.2' - db-type: 'mysql' - prefer-lowest: 'prefer-lowest' + db-type: mysql + prefer-lowest: prefer-lowest steps: - name: Setup MySQL latest @@ -33,7 +41,7 @@ jobs: if: matrix.db-type == 'pgsql' && matrix.php-version == '7.2' run: docker run --rm --name=postgres -e POSTGRES_PASSWORD=postgres -e POSTGRES_DB=cakephp -p 5432:5432 -d postgres:9.4 - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -50,14 +58,14 @@ jobs: run: echo "::set-output name=date::$(date +'%Y-%m')" - name: Cache composer dependencies - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}-${{ matrix.prefer-lowest }} - name: Composer install run: | - if [[ ${{ matrix.php-version }} == '8.1' ]]; then + if [[ ${{ matrix.php-version }} == '8.2' ]]; then composer install --ignore-platform-req=php elif ${{ matrix.prefer-lowest == 'prefer-lowest' }}; then composer update --prefer-lowest --prefer-stable @@ -89,26 +97,30 @@ jobs: if [[ ${{ matrix.db-type }} == 'mysql' ]]; then export MYSQL_DSN='mysql://root:root@127.0.0.1/phinx'; fi if [[ ${{ matrix.db-type }} == 'pgsql' ]]; then export PGSQL_DSN='pgsql://postgres:postgres@127.0.0.1/phinx'; fi - if [[ ${{ matrix.php-version }} == '8.0' ]]; then + if [[ ${{ matrix.php-version }} == '8.1' ]]; then export CODECOVERAGE=1 && vendor/bin/phpunit --verbose --coverage-clover=coverage.xml else vendor/bin/phpunit fi + - name: Prefer lowest check + if: matrix.prefer-lowest == 'prefer-lowest' + run: composer require --dev dereuromark/composer-prefer-lowest && vendor/bin/validate-prefer-lowest -m + - name: Submit code coverage - if: matrix.php-version == '8.0' - uses: codecov/codecov-action@v1 + if: matrix.php-version == '8.1' + uses: codecov/codecov-action@v3 testsuite-windows: runs-on: windows-2019 - name: Windows - PHP 7.4 & SQL Server + name: Windows - PHP 8.1 & SQL Server env: EXTENSIONS: pdo_sqlsrv - PHP_VERSION: '7.4' + PHP_VERSION: '8.1' steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Get date part for cache key id: key-date @@ -123,7 +135,7 @@ jobs: key: ${{ steps.key-date.outputs.date }} - name: Cache PHP extensions - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ steps.php-ext-cache.outputs.dir }} key: ${{ runner.os }}-php-ext-${{ steps.php-ext-cache.outputs.key }} @@ -149,7 +161,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache composer dependencies - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }}-${{ matrix.prefer-lowest }} @@ -165,19 +177,19 @@ jobs: vendor/bin/phpunit --verbose --coverage-clover=coverage.xml - name: Submit code coverage - uses: codecov/codecov-action@v1 + uses: codecov/codecov-action@v3 cs-stan: name: Coding Standard & Static Analysis runs-on: ubuntu-20.04 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 with: - php-version: '7.2' + php-version: '7.4' coverage: none - name: Get composer cache directory @@ -189,7 +201,7 @@ jobs: run: echo "::set-output name=date::$(date +'%Y-%m')" - name: Cache composer dependencies - uses: actions/cache@v1 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ steps.key-date.outputs.date }}-${{ hashFiles('composer.json') }} @@ -201,4 +213,5 @@ jobs: run: vendor/bin/phpcs --report=checkstyle -np app/ src/ tests/ - name: Run phpstan + if: always() run: vendor/bin/phpstan.phar analyse --error-format=github diff --git a/.github/workflows/deploy_docs_0x.yml b/.github/workflows/deploy_docs_0x.yml new file mode 100644 index 000000000..9a06695c4 --- /dev/null +++ b/.github/workflows/deploy_docs_0x.yml @@ -0,0 +1,28 @@ +--- +name: 'deploy_docs_0x' + +on: + push: + tags: + - v0.* + workflow_dispatch: + inputs: + branch: + description: Branch to run on + default: master + required: true + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Cloning repo + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Push to dokku + uses: dokku/github-action@master + with: + git_remote_url: 'ssh://dokku@apps.cakephp.org:22/phinx-docs' + ssh_private_key: ${{ secrets.DOKKU_SSH_PRIVATE_KEY }} diff --git a/.github/workflows/phar.yml b/.github/workflows/phar.yml index dc625be68..3aae0548f 100644 --- a/.github/workflows/phar.yml +++ b/.github/workflows/phar.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v2 + uses: actions/checkout@v3 - name: Setup PHP uses: shivammathur/setup-php@v2 @@ -22,7 +22,7 @@ jobs: run: echo "::set-output name=dir::$(composer config cache-files-dir)" - name: Cache dependencies - uses: actions/cache@v2 + uses: actions/cache@v3 with: path: ${{ steps.composer-cache.outputs.dir }} key: ${{ runner.os }}-composer-${{ hashFiles('**/composer.lock') }} diff --git a/composer.json b/composer.json index 8a1b680d8..3802f3f6b 100644 --- a/composer.json +++ b/composer.json @@ -2,34 +2,45 @@ "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"], + "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" - }], + "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": ">=7.2", "cakephp/database": "^4.0", "psr/container": "^1.0 || ^2.0", - "symfony/console": "^3.4|^4.0|^5.0", - "symfony/config": "^3.4|^4.0|^5.0" + "symfony/console": "^3.4|^4.0|^5.0|^6.0", + "symfony/config": "^3.4|^4.0|^5.0|^6.0" }, "require-dev": { "ext-json": "*", @@ -62,8 +73,15 @@ "cs-check": "phpcs -np app/ src/ tests/", "cs-fix": "phpcbf -np app/ src/ tests/", "stan": "phpstan analyse src/", - "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:^0.12 && mv composer.backup composer.json", + "stan-setup": "cp composer.json composer.backup && composer require --dev phpstan/phpstan:~1.5.0 && mv composer.backup composer.json", "test": "phpunit --colors=always" }, - "bin": ["bin/phinx"] + "bin": [ + "bin/phinx" + ], + "config": { + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true + } + } } diff --git a/docs.Dockerfile b/docs.Dockerfile index 97da985ca..f08ad3832 100644 --- a/docs.Dockerfile +++ b/docs.Dockerfile @@ -5,12 +5,18 @@ 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 + make website LANGS="en" SOURCE=/data/docs DEST=/data/website # Build a small nginx container with just the static site in it. -FROM nginx:1.15-alpine +FROM markstory/cakephp-docs-builder:runtime as runtime +# Configure search index script +ENV LANGS="en" +ENV SEARCH_SOURCE="/usr/share/nginx/html" +ENV SEARCH_URL_PREFIX="/phinx/0" + +COPY --from=builder /data/docs /data/docs COPY --from=builder /data/website /data/website COPY --from=builder /data/docs-builder/nginx.conf /etc/nginx/conf.d/default.conf diff --git a/docs/config/all.py b/docs/config/all.py index 0276971e8..df79d5327 100644 --- a/docs/config/all.py +++ b/docs/config/all.py @@ -25,7 +25,7 @@ ] # Languages available. -languages = ['en', 'es', 'fr', 'ja'] +languages = ['en'] # The GitHub branch name for this version of the docs # for edit links to point at. diff --git a/docs/en/configuration.rst b/docs/en/configuration.rst index 5a3eeed7c..f26b3f3e5 100644 --- a/docs/en/configuration.rst +++ b/docs/en/configuration.rst @@ -323,9 +323,9 @@ specified directly as connection options. default_migration_table: phinxlog default_environment: development development: - dsn: %%DATABASE_URL%% + dsn: '%%DATABASE_URL%%' production: - dsn: %%DATABASE_URL%% + dsn: '%%DATABASE_URL%%' name: production_database If the supplied DSN is invalid, then it is completely ignored. @@ -391,6 +391,18 @@ Declaring an SQLite database uses a simplified structure: adapter: sqlite memory: true # Setting memory to *any* value overrides name +Starting with PHP 8.1 the SQlite adapter supports ``cache`` and ``mode`` +query parameters by using the `URI scheme `_ as long as ``open_basedir`` is unset. + +.. code-block:: yaml + + environments: + testing: + adapter: sqlite + name: my_app + mode: memory # Determines if the new database is opened read-only, read-write, read-write and created if it does not exist, or that the database is a pure in-memory database that never interacts with disk, respectively. + cache: shared # Determines if the new database is opened using shared cache mode or with a private cache. + SQL Server ````````````````` diff --git a/docs/en/contents.rst b/docs/en/contents.rst index 4723181b2..900f6ed2e 100644 --- a/docs/en/contents.rst +++ b/docs/en/contents.rst @@ -2,7 +2,6 @@ Contents ######## .. toctree:: - :maxdepth: 2 :caption: Phinx intro diff --git a/docs/en/index.rst b/docs/en/index.rst index aebe734e8..530c8c965 100644 --- a/docs/en/index.rst +++ b/docs/en/index.rst @@ -1,3 +1,5 @@ +:orphan: + Phinx Documentation =================== diff --git a/docs/en/migrations.rst b/docs/en/migrations.rst index f09b7ce90..f31607209 100644 --- a/docs/en/migrations.rst +++ b/docs/en/migrations.rst @@ -305,15 +305,15 @@ insert methods in your migrations. */ public function up() { + $table = $this->table('status'); + // inserting only one row $singleRow = [ 'id' => 1, 'name' => 'In Progress' ]; - $table = $this->table('status'); - $table->insert($singleRow); - $table->saveData(); + $table->insert($singleRow)->saveData(); // inserting multiple rows $rows = [ @@ -327,7 +327,7 @@ insert methods in your migrations. ] ]; - $this->table('status')->insert($rows)->save(); + $table->insert($rows)->saveData(); } /** @@ -1154,7 +1154,8 @@ To rename a column, access an instance of the Table object then call the public function up() { $table = $this->table('users'); - $table->renameColumn('bio', 'biography'); + $table->renameColumn('bio', 'biography') + ->save(); } /** @@ -1163,14 +1164,16 @@ To rename a column, access an instance of the Table object then call the public function down() { $table = $this->table('users'); - $table->renameColumn('biography', 'bio'); + $table->renameColumn('biography', 'bio') + ->save(); } } Adding a Column After Another Column ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -When adding a column you can dictate its position using the ``after`` option. +When adding a column with the MySQL adapter, you can dictate its position using the ``after`` option, +where its value is the name of the column to position it after. .. code-block:: php @@ -1191,6 +1194,10 @@ When adding a column you can dictate its position using the ``after`` option. } } +This would create the new column ``city`` and position it after the ``email`` column. You +can use the `\Phinx\Db\Adapter\MysqlAdapter\FIRST` constant to specify that the new column should +created as the first column in that table. + Dropping a Column ~~~~~~~~~~~~~~~~~ @@ -1411,6 +1418,24 @@ The SQL Server and PostgreSQL adapters also supports ``include`` (non-key) colum } } +In addition PostgreSQL adapters also supports Generalized Inverted Index ``gin`` indexes. + +.. code-block:: php + + table('users'); + $table->addColumn('address', 'string') + ->addIndex('address', ['type' => 'gin']) + ->create(); + } + } Removing indexes is as easy as calling the ``removeIndex()`` method. You must call this method for each index. diff --git a/docs/en/namespaces.rst b/docs/en/namespaces.rst index c679687be..b7496fac7 100644 --- a/docs/en/namespaces.rst +++ b/docs/en/namespaces.rst @@ -1,3 +1,5 @@ +:orphan: + .. index:: single: Supporting namespaces diff --git a/docs/en/seeding.rst b/docs/en/seeding.rst index 8ae28db1d..a41dfc7b2 100644 --- a/docs/en/seeding.rst +++ b/docs/en/seeding.rst @@ -160,47 +160,6 @@ within your seed class and then use the `insert()` method to insert data: 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 `_ 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 - - $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 ----------------- diff --git a/docs/es/commands.rst b/docs/es/commands.rst deleted file mode 100644 index 685c22932..000000000 --- a/docs/es/commands.rst +++ /dev/null @@ -1,292 +0,0 @@ -. 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 ` 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 ` 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="" - -Tambien puedes suministrar un modelo de clase general. Esta clase deberá implementar la interfaz ``Phinx\Migration\CreationInterface``. - -.. code-block:: bash - - $ phinx create MyNewMigration --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 ` 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 ` 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:: - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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()``:: - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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; - } - - } diff --git a/docs/es/conf.py b/docs/es/conf.py deleted file mode 100644 index 4691ece6a..000000000 --- a/docs/es/conf.py +++ /dev/null @@ -1,9 +0,0 @@ -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' diff --git a/docs/es/contents.rst b/docs/es/contents.rst deleted file mode 100644 index 9bbcc9cbe..000000000 --- a/docs/es/contents.rst +++ /dev/null @@ -1,8 +0,0 @@ -Contents -######## - -.. toctree:: - :maxdepth: 2 - :caption: Phinx - - commands diff --git a/docs/fr/commands.rst b/docs/fr/commands.rst deleted file mode 100644 index c9c833460..000000000 --- a/docs/fr/commands.rst +++ /dev/null @@ -1,339 +0,0 @@ -.. 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 ` 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 ` 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="" - -You can also supply a template generating class. This class must implement the -interface ``Phinx\Migration\CreationInterface``. - -.. code-block:: bash - - $ phinx create MyNewMigration --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 ` 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 ` 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 - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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 - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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 ``__ which will show current -migration status by default. To run migrations up, use ``__ -and to rollback use ``__. - -**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; - } - - } diff --git a/docs/fr/conf.py b/docs/fr/conf.py deleted file mode 100644 index b02032efa..000000000 --- a/docs/fr/conf.py +++ /dev/null @@ -1,9 +0,0 @@ -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' diff --git a/docs/fr/contents.rst b/docs/fr/contents.rst deleted file mode 100644 index e5dae97bc..000000000 --- a/docs/fr/contents.rst +++ /dev/null @@ -1,11 +0,0 @@ -Contenus -======== - -.. toctree:: - :maxdepth: 2 - - index - migrations - seeding - commands - configuration diff --git a/docs/fr/index.rst b/docs/fr/index.rst deleted file mode 100644 index ac9d0a04d..000000000 --- a/docs/fr/index.rst +++ /dev/null @@ -1,57 +0,0 @@ -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 `_ 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 diff --git a/docs/fr/seeding.rst b/docs/fr/seeding.rst deleted file mode 100644 index 235228547..000000000 --- a/docs/fr/seeding.rst +++ /dev/null @@ -1,217 +0,0 @@ -.. 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:: - - '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 `_ in your seed classes. -Simply install it using Composer: - -.. code-block:: bash - - $ composer require fzaninotto/faker - -Then use it in your seed classes:: - - $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:: - - '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. diff --git a/docs/ja/commands.rst b/docs/ja/commands.rst deleted file mode 100644 index 51c7bf27d..000000000 --- a/docs/ja/commands.rst +++ /dev/null @@ -1,338 +0,0 @@ -.. index:: - single: Commands - -コマンド -######## - -Phinx は多くのコマンドを使用して実行されます。 - -マイグレーションコマンド -======================== - -init コマンド ----------------- - -init コマンド (initialize の略) は、Phinx のプロジェクトを準備するために使用されます。 -このコマンドはプロジェクトディレクトリーのルートに ``phinx.yml`` ファイルを生成します。 - -.. code-block:: bash - - $ cd yourapp - $ phinx init . - -このファイルをテキストエディターで開き、プロジェクトの設定を行います。 -詳しくは :doc:`設定 ` の章をご覧下さい。 - -create コマンド ---------------- - -create コマンドは、新しいマイグレーションファイルを作成するために使用されます。 -1つの引数、つまりマイグレーション名が必要です。 -マイグレーション名は、キャメルケース形式で指定する必要があります。 - -.. code-block:: bash - - $ phinx create MyNewMigration - -新しいマイグレーションファイルをテキストエディターで開き、データベースの変更を追加します。 -Phinx は ``phinx.yml`` ファイルで指定されたパスを使ってマイグレーションファイルを作成します。 -詳しくは :doc:`設定 ` の章をご覧下さい。 - -代替のテンプレートファイル名を指定することで、 -Phinx が使用するテンプレートファイルを上書きすることができます。 - -.. code-block:: bash - - $ phinx create MyNewMigration --template="" - -テンプレート生成クラスを提供することもできます。このクラスはインタフェース -``Phinx\Migration\CreationInterface`` を実装しなければなりません。 - -.. code-block:: bash - - $ phinx create MyNewMigration --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:`設定 ` の章をご覧下さい。 - -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:`設定 ` の章をご覧下さい。 - -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 - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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 - - [ - "migrations" => "application/migrations" - ], - "environments" => [ - "default_migration_table" => "phinxlog", - "default_environment" => "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 - -これはデフォルトで現在のマイグレーションの状態を表示する ``__ -にローカルウェブサーバーを作成します。マイグレーションを実行するには、 -``__ を使用し、ロールバックには -``__ を使用します。 - -**付属のウェブアプリは一例に過ぎません、本番環境では使用しないでください!** - -.. 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; - } - - } diff --git a/docs/ja/conf.py b/docs/ja/conf.py deleted file mode 100644 index 5871da648..000000000 --- a/docs/ja/conf.py +++ /dev/null @@ -1,9 +0,0 @@ -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' diff --git a/docs/ja/contents.rst b/docs/ja/contents.rst deleted file mode 100644 index abb198fd1..000000000 --- a/docs/ja/contents.rst +++ /dev/null @@ -1,12 +0,0 @@ -コンテンツ -=========== - -.. toctree:: - :maxdepth: 2 - :caption: Phinx - - index - migrations - seeding - commands - configuration diff --git a/docs/ja/index.rst b/docs/ja/index.rst deleted file mode 100644 index 65bd83c68..000000000 --- a/docs/ja/index.rst +++ /dev/null @@ -1,60 +0,0 @@ -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 `_ のウェブサイトを見てください。 - -.. 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 - diff --git a/docs/ja/seeding.rst b/docs/ja/seeding.rst deleted file mode 100644 index 92680bee0..000000000 --- a/docs/ja/seeding.rst +++ /dev/null @@ -1,214 +0,0 @@ -.. index:: - single: Database Seeding - -データベースの初期データ投入 -============================ - -バージョン0.5.0 では、Phinx はデータベースにテストデータをシードするためのサポートを導入しました。 -シードクラスは、作成済みのデータをデータベースに簡単に投入するための優れた方法です。 -デフォルトでは ``seeds`` ディレクトリーに保存されます。 ただし、このパスは設定ファイルで変更できます。 - -.. note:: - - データベースのシードは完全にオプションで、 - Phinx はデフォルトで ``seeds`` ディレクトリーを作成しません。 - -シードクラスの新規作成 ----------------------- - -Phinx には、新しいシードクラスを簡単に生成するコマンドが含まれています。 - -.. code-block:: bash - - $ php vendor/bin/phinx seed:create UserSeeder - -複数のシードのパスを指定した場合は、新しいシードクラスを作成するパスを選択するように求められます。 - -以下は、スケルトンテンプレートを元にしています。 :: - - '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 ライブラリー `_ -を使うのは簡単です。Composer を使用してインストールするだけです。 - -.. code-block:: bash - - $ composer require fzaninotto/faker - -そして、シードクラスの中で、それを使用してください。 :: - - $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`` コマンドを使って -テーブルを空にすることを容易にします。 :: - - '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 のシード機能は、テストデータをデータベースに簡単かつ繰り返し挿入するための -簡単なメカニズムを提供します。 diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon index dd036a951..03587fb2e 100644 --- a/phpstan-baseline.neon +++ b/phpstan-baseline.neon @@ -1,7 +1,27 @@ parameters: ignoreErrors: - - message: "#^Call to function is_subclass_of\\(\\) with non\\-empty\\-string and 'Phinx\\\\\\\\Migration…' will always evaluate to false\\.$#" + message: "#^Variable \\$tval on left side of \\?\\? always exists and is not nullable\\.$#" + count: 1 + path: src/Phinx/Config/Config.php + + - + message: "#^Expression on left side of \\?\\? is not nullable\\.$#" + count: 1 + path: src/Phinx/Db/Adapter/MysqlAdapter.php + + - + message: "#^Ternary operator condition is always true\\.$#" count: 2 - path: src/Phinx/Console/Command/Create.php + path: src/Phinx/Db/Adapter/SqlServerAdapter.php + + - + message: "#^Property Phinx\\\\Migration\\\\Manager\\\\Environment\\:\\:\\$adapter \\(Phinx\\\\Db\\\\Adapter\\\\AdapterInterface\\) in isset\\(\\) is not nullable\\.$#" + count: 1 + path: src/Phinx/Migration/Manager/Environment.php + + - + message: "#^Unreachable statement \\- code above always terminates\\.$#" + count: 1 + path: src/Phinx/Migration/Manager/Environment.php diff --git a/phpstan.neon b/phpstan.neon index f4eded17b..703cfce6e 100644 --- a/phpstan.neon +++ b/phpstan.neon @@ -10,4 +10,3 @@ parameters: - src/ ignoreErrors: - '#Unsafe usage of new static\(\)\.#' - - '#Parameter \#2 \$callback of function array_filter expects .*callable\(mixed, mixed\): bool.*, .+ given.#' diff --git a/src/Phinx/Config/Config.php b/src/Phinx/Config/Config.php index ebe8c5b32..e918ba4bf 100644 --- a/src/Phinx/Config/Config.php +++ b/src/Phinx/Config/Config.php @@ -144,7 +144,7 @@ public static function fromPhp(string $configFilePath): ConfigInterface */ public function getEnvironments(): ?array { - if (isset($this->values) && isset($this->values['environments'])) { + if (isset($this->values['environments'])) { $environments = []; foreach ($this->values['environments'] as $key => $value) { if (is_array($value)) { diff --git a/src/Phinx/Console/Command/AbstractCommand.php b/src/Phinx/Console/Command/AbstractCommand.php index 841ca6724..c9490d62b 100644 --- a/src/Phinx/Console/Command/AbstractCommand.php +++ b/src/Phinx/Console/Command/AbstractCommand.php @@ -64,6 +64,11 @@ abstract class AbstractCommand extends Command */ protected $manager; + /** + * @var int + */ + protected $verbosityLevel = OutputInterface::OUTPUT_NORMAL | OutputInterface::VERBOSITY_NORMAL; + /** * Exit code for when command executes successfully * @@ -102,6 +107,7 @@ protected function configure(): void { $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'); + $this->addOption('--no-info', null, InputOption::VALUE_NONE, 'Hides all debug information'); } /** @@ -113,6 +119,10 @@ protected function configure(): void */ public function bootstrap(InputInterface $input, OutputInterface $output): void { + if ($input->hasParameterOption('--no-info')) { + $this->verbosityLevel = OutputInterface::VERBOSITY_VERBOSE; + } + if (!$this->hasConfig()) { $this->loadConfig($input, $output); } @@ -121,26 +131,26 @@ public function bootstrap(InputInterface $input, OutputInterface $output): void $bootstrap = $this->getConfig()->getBootstrapFile(); if ($bootstrap) { - $output->writeln('using bootstrap ' . Util::relativePath($bootstrap) . ' '); + $output->writeln('using bootstrap ' . Util::relativePath($bootstrap) . ' ', $this->verbosityLevel); Util::loadPhpFile($bootstrap, $input, $output, $this); } // report the paths $paths = $this->getConfig()->getMigrationPaths(); - $output->writeln('using migration paths '); + $output->writeln('using migration paths ', $this->verbosityLevel); foreach (Util::globAll($paths) as $path) { - $output->writeln(' - ' . realpath($path) . ''); + $output->writeln(' - ' . realpath($path) . '', $this->verbosityLevel); } try { $paths = $this->getConfig()->getSeedPaths(); - $output->writeln('using seed paths '); + $output->writeln('using seed paths ', $this->verbosityLevel); foreach (Util::globAll($paths) as $path) { - $output->writeln(' - ' . realpath($path) . ''); + $output->writeln(' - ' . realpath($path) . '', $this->verbosityLevel); } } catch (UnexpectedValueException $e) { // do nothing as seeds are optional @@ -279,7 +289,7 @@ protected function locateConfigFile(InputInterface $input): string protected function loadConfig(InputInterface $input, OutputInterface $output): void { $configFilePath = $this->locateConfigFile($input); - $output->writeln('using config file ' . Util::relativePath($configFilePath)); + $output->writeln('using config file ' . Util::relativePath($configFilePath), $this->verbosityLevel); /** @var string|null $parser */ $parser = $input->getOption('parser'); @@ -318,7 +328,7 @@ protected function loadConfig(InputInterface $input, OutputInterface $output): v throw new InvalidArgumentException(sprintf('\'%s\' is not a valid parser.', $parser)); } - $output->writeln('using config parser ' . $parser); + $output->writeln('using config parser ' . $parser, $this->verbosityLevel); $this->setConfig($config); } @@ -334,6 +344,7 @@ protected function loadManager(InputInterface $input, OutputInterface $output): { if ($this->getManager() === null) { $manager = new Manager($this->getConfig(), $input, $output); + $manager->setVerbosityLevel($this->verbosityLevel); $container = $this->getConfig()->getContainer(); if ($container !== null) { $manager->setContainer($container); diff --git a/src/Phinx/Console/Command/Breakpoint.php b/src/Phinx/Console/Command/Breakpoint.php index 27e1c8070..0b7bc1f23 100644 --- a/src/Phinx/Console/Command/Breakpoint.php +++ b/src/Phinx/Console/Command/Breakpoint.php @@ -69,9 +69,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($environment === null) { $environment = $this->getConfig()->getDefaultEnvironment(); - $output->writeln('warning no environment specified, defaulting to: ' . $environment); + $output->writeln('warning no environment specified, defaulting to: ' . $environment, $this->verbosityLevel); } else { - $output->writeln('using environment ' . $environment); + $output->writeln('using environment ' . $environment, $this->verbosityLevel); } if (!$this->getConfig()->hasEnvironment($environment)) { diff --git a/src/Phinx/Console/Command/Create.php b/src/Phinx/Console/Command/Create.php index 89a9a28a5..4767a8d7b 100644 --- a/src/Phinx/Console/Command/Create.php +++ b/src/Phinx/Console/Command/Create.php @@ -307,17 +307,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int $creationClass->postMigrationCreation($filePath, $className, $this->getConfig()->getMigrationBaseClassName()); } - $output->writeln('using migration base class ' . $classes['$useClassName']); + $output->writeln('using migration base class ' . $classes['$useClassName'], $this->verbosityLevel); if (!empty($altTemplate)) { - $output->writeln('using alternative template ' . $altTemplate); + $output->writeln('using alternative template ' . $altTemplate, $this->verbosityLevel); } elseif (!empty($creationClassName)) { - $output->writeln('using template creation class ' . $creationClassName); + $output->writeln('using template creation class ' . $creationClassName, $this->verbosityLevel); } else { - $output->writeln('using default template'); + $output->writeln('using default template', $this->verbosityLevel); } - $output->writeln('created ' . Util::relativePath($filePath)); + $output->writeln('created ' . Util::relativePath($filePath), $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/Command/ListAliases.php b/src/Phinx/Console/Command/ListAliases.php index 99b9dcd81..bcdfa7761 100644 --- a/src/Phinx/Console/Command/ListAliases.php +++ b/src/Phinx/Console/Command/ListAliases.php @@ -61,7 +61,8 @@ function ($alias, $class) use ($maxAliasLength, $maxClassLength) { array_keys($aliases), $aliases ) - ) + ), + $this->verbosityLevel ); } else { $output->writeln( diff --git a/src/Phinx/Console/Command/Migrate.php b/src/Phinx/Console/Command/Migrate.php index b61a281f4..2da1f00a3 100644 --- a/src/Phinx/Console/Command/Migrate.php +++ b/src/Phinx/Console/Command/Migrate.php @@ -69,9 +69,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($environment === null) { $environment = $this->getConfig()->getDefaultEnvironment(); - $output->writeln('warning no environment specified, defaulting to: ' . $environment); + $output->writeln('warning no environment specified, defaulting to: ' . $environment, $this->verbosityLevel); } else { - $output->writeln('using environment ' . $environment); + $output->writeln('using environment ' . $environment, $this->verbosityLevel); } if (!$this->getConfig()->hasEnvironment($environment)) { @@ -82,15 +82,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int $envOptions = $this->getConfig()->getEnvironment($environment); if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); + $output->writeln('using adapter ' . $envOptions['adapter'], $this->verbosityLevel); } if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); + $output->writeln('using wrapper ' . $envOptions['wrapper'], $this->verbosityLevel); } if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); + $output->writeln('using database ' . $envOptions['name'], $this->verbosityLevel); } else { $output->writeln('Could not determine database name! Please specify a database name in your config file.'); @@ -98,17 +98,17 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (isset($envOptions['table_prefix'])) { - $output->writeln('using table prefix ' . $envOptions['table_prefix']); + $output->writeln('using table prefix ' . $envOptions['table_prefix'], $this->verbosityLevel); } if (isset($envOptions['table_suffix'])) { - $output->writeln('using table suffix ' . $envOptions['table_suffix']); + $output->writeln('using table suffix ' . $envOptions['table_suffix'], $this->verbosityLevel); } $versionOrder = $this->getConfig()->getVersionOrder(); - $output->writeln('ordering by ' . $versionOrder . ' time'); + $output->writeln('ordering by ' . $versionOrder . ' time', $this->verbosityLevel); if ($fake) { - $output->writeln('warning performing fake migrations'); + $output->writeln('warning performing fake migrations', $this->verbosityLevel); } try { @@ -130,8 +130,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int return self::CODE_ERROR; } - $output->writeln(''); - $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . ''); + $output->writeln('', $this->verbosityLevel); + $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '', $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/Command/Rollback.php b/src/Phinx/Console/Command/Rollback.php index fe5ba934d..03a6cd126 100644 --- a/src/Phinx/Console/Command/Rollback.php +++ b/src/Phinx/Console/Command/Rollback.php @@ -79,9 +79,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($environment === null) { $environment = $config->getDefaultEnvironment(); - $output->writeln('warning no environment specified, defaulting to: ' . $environment); + $output->writeln('warning no environment specified, defaulting to: ' . $environment, $this->verbosityLevel); } else { - $output->writeln('using environment ' . $environment); + $output->writeln('using environment ' . $environment, $this->verbosityLevel); } if (!$this->getConfig()->hasEnvironment($environment)) { @@ -92,22 +92,22 @@ protected function execute(InputInterface $input, OutputInterface $output): int $envOptions = $config->getEnvironment($environment); if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); + $output->writeln('using adapter ' . $envOptions['adapter'], $this->verbosityLevel); } if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); + $output->writeln('using wrapper ' . $envOptions['wrapper'], $this->verbosityLevel); } if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); + $output->writeln('using database ' . $envOptions['name'], $this->verbosityLevel); } $versionOrder = $this->getConfig()->getVersionOrder(); - $output->writeln('ordering by ' . $versionOrder . ' time'); + $output->writeln('ordering by ' . $versionOrder . ' time', $this->verbosityLevel); if ($fake) { - $output->writeln('warning performing fake rollbacks'); + $output->writeln('warning performing fake rollbacks', $this->verbosityLevel); } // rollback the specified environment @@ -123,8 +123,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $this->getManager()->rollback($environment, $target, $force, $targetMustMatchVersion, $fake); $end = microtime(true); - $output->writeln(''); - $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . ''); + $output->writeln('', $this->verbosityLevel); + $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '', $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/Command/SeedCreate.php b/src/Phinx/Console/Command/SeedCreate.php index 8ba5f232f..afe06bcea 100644 --- a/src/Phinx/Console/Command/SeedCreate.php +++ b/src/Phinx/Console/Command/SeedCreate.php @@ -198,8 +198,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int )); } - $output->writeln('using seed base class ' . $classes['$useClassName']); - $output->writeln('created ' . Util::relativePath($filePath)); + $output->writeln('using seed base class ' . $classes['$useClassName'], $this->verbosityLevel); + $output->writeln('created ' . Util::relativePath($filePath), $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/Command/SeedRun.php b/src/Phinx/Console/Command/SeedRun.php index 6f1b3e731..88d04f6f7 100644 --- a/src/Phinx/Console/Command/SeedRun.php +++ b/src/Phinx/Console/Command/SeedRun.php @@ -62,9 +62,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($environment === null) { $environment = $this->getConfig()->getDefaultEnvironment(); - $output->writeln('warning no environment specified, defaulting to: ' . $environment); + $output->writeln('warning no environment specified, defaulting to: ' . $environment, $this->verbosityLevel); } else { - $output->writeln('using environment ' . $environment); + $output->writeln('using environment ' . $environment, $this->verbosityLevel); } if (!$this->getConfig()->hasEnvironment($environment)) { @@ -75,15 +75,15 @@ protected function execute(InputInterface $input, OutputInterface $output): int $envOptions = $this->getConfig()->getEnvironment($environment); if (isset($envOptions['adapter'])) { - $output->writeln('using adapter ' . $envOptions['adapter']); + $output->writeln('using adapter ' . $envOptions['adapter'], $this->verbosityLevel); } if (isset($envOptions['wrapper'])) { - $output->writeln('using wrapper ' . $envOptions['wrapper']); + $output->writeln('using wrapper ' . $envOptions['wrapper'], $this->verbosityLevel); } if (isset($envOptions['name'])) { - $output->writeln('using database ' . $envOptions['name']); + $output->writeln('using database ' . $envOptions['name'], $this->verbosityLevel); } else { $output->writeln('Could not determine database name! Please specify a database name in your config file.'); @@ -91,10 +91,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if (isset($envOptions['table_prefix'])) { - $output->writeln('using table prefix ' . $envOptions['table_prefix']); + $output->writeln('using table prefix ' . $envOptions['table_prefix'], $this->verbosityLevel); } if (isset($envOptions['table_suffix'])) { - $output->writeln('using table suffix ' . $envOptions['table_suffix']); + $output->writeln('using table suffix ' . $envOptions['table_suffix'], $this->verbosityLevel); } $start = microtime(true); @@ -111,8 +111,8 @@ protected function execute(InputInterface $input, OutputInterface $output): int $end = microtime(true); - $output->writeln(''); - $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . ''); + $output->writeln('', $this->verbosityLevel); + $output->writeln('All Done. Took ' . sprintf('%.4fs', $end - $start) . '', $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/Command/Status.php b/src/Phinx/Console/Command/Status.php index be6b893c7..e656525c1 100644 --- a/src/Phinx/Console/Command/Status.php +++ b/src/Phinx/Console/Command/Status.php @@ -61,9 +61,9 @@ protected function execute(InputInterface $input, OutputInterface $output): int if ($environment === null) { $environment = $this->getConfig()->getDefaultEnvironment(); - $output->writeln('warning no environment specified, defaulting to: ' . $environment); + $output->writeln('warning no environment specified, defaulting to: ' . $environment, $this->verbosityLevel); } else { - $output->writeln('using environment ' . $environment); + $output->writeln('using environment ' . $environment, $this->verbosityLevel); } if (!$this->getConfig()->hasEnvironment($environment)) { @@ -73,10 +73,10 @@ protected function execute(InputInterface $input, OutputInterface $output): int } if ($format !== null) { - $output->writeln('using format ' . $format); + $output->writeln('using format ' . $format, $this->verbosityLevel); } - $output->writeln('ordering by ' . $this->getConfig()->getVersionOrder() . ' time'); + $output->writeln('ordering by ' . $this->getConfig()->getVersionOrder() . ' time', $this->verbosityLevel); // print the status $result = $this->getManager()->printStatus($environment, $format); diff --git a/src/Phinx/Console/Command/Test.php b/src/Phinx/Console/Command/Test.php index 4ef359e1f..af0f7cd21 100644 --- a/src/Phinx/Console/Command/Test.php +++ b/src/Phinx/Console/Command/Test.php @@ -82,7 +82,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int )); } - $output->writeln(sprintf('validating environment %s', $envName)); + $output->writeln(sprintf('validating environment %s', $envName), $this->verbosityLevel); $environment = new Environment( $envName, $this->getConfig()->getEnvironment($envName) @@ -91,7 +91,7 @@ protected function execute(InputInterface $input, OutputInterface $output): int $environment->getAdapter()->connect(); } - $output->writeln('success!'); + $output->writeln('success!', $this->verbosityLevel); return self::CODE_SUCCESS; } diff --git a/src/Phinx/Console/PhinxApplication.php b/src/Phinx/Console/PhinxApplication.php index 3d78a6fab..5ff32db98 100644 --- a/src/Phinx/Console/PhinxApplication.php +++ b/src/Phinx/Console/PhinxApplication.php @@ -60,9 +60,11 @@ public function doRun(InputInterface $input, OutputInterface $output): int { // 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(''); + if ($input->hasParameterOption('--no-info') === false) { + if (($input->hasParameterOption(['--help', '-h']) !== false) || ($input->getFirstArgument() !== null && $input->getFirstArgument() !== 'list')) { + $output->writeln($this->getLongVersion()); + $output->writeln(''); + } } return parent::doRun($input, $output); diff --git a/src/Phinx/Db/Adapter/MysqlAdapter.php b/src/Phinx/Db/Adapter/MysqlAdapter.php index 9ad52e26d..f414a2968 100644 --- a/src/Phinx/Db/Adapter/MysqlAdapter.php +++ b/src/Phinx/Db/Adapter/MysqlAdapter.php @@ -80,6 +80,12 @@ class MysqlAdapter extends PdoAdapter public const INT_REGULAR = 1073741823; public const INT_BIG = 2147483647; + public const INT_DISPLAY_TINY = 4; + public const INT_DISPLAY_SMALL = 6; + public const INT_DISPLAY_MEDIUM = 8; + public const INT_DISPLAY_REGULAR = 11; + public const INT_DISPLAY_BIG = 20; + public const BIT = 64; public const TYPE_YEAR = 'year'; @@ -131,6 +137,11 @@ public function connect(): void $driverOptions[PDO::ATTR_DEFAULT_FETCH_MODE] = constant('\PDO::FETCH_' . strtoupper($options['fetch_mode'])); } + // pass \PDO::ATTR_PERSISTENT to driver options instead of useless setting it after instantiation + if (isset($options['attr_persistent'])) { + $driverOptions[PDO::ATTR_PERSISTENT] = $options['attr_persistent']; + } + // support arbitrary \PDO::MYSQL_ATTR_* driver options and pass them to PDO // http://php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants foreach ($options as $key => $option) { @@ -1026,12 +1037,28 @@ public function getSqlType($type, ?int $limit = null): array case static::PHINX_TYPE_BIT: return ['name' => 'bit', 'limit' => $limit ?: 64]; case static::PHINX_TYPE_BIG_INTEGER: + if ($limit === static::INT_BIG) { + $limit = static::INT_DISPLAY_BIG; + } + return ['name' => 'bigint', 'limit' => $limit ?: 20]; case static::PHINX_TYPE_MEDIUM_INTEGER: + if ($limit === static::INT_MEDIUM) { + $limit = static::INT_DISPLAY_MEDIUM; + } + return ['name' => 'mediumint', 'limit' => $limit ?: 8]; case static::PHINX_TYPE_SMALL_INTEGER: + if ($limit === static::INT_SMALL) { + $limit = static::INT_DISPLAY_SMALL; + } + return ['name' => 'smallint', 'limit' => $limit ?: 6]; case static::PHINX_TYPE_TINY_INTEGER: + if ($limit === static::INT_TINY) { + $limit = static::INT_DISPLAY_TINY; + } + return ['name' => 'tinyint', 'limit' => $limit ?: 4]; case static::PHINX_TYPE_INTEGER: if ($limit && $limit >= static::INT_TINY) { @@ -1044,11 +1071,11 @@ public function getSqlType($type, ?int $limit = null): array 'tinyint' => static::INT_TINY, ]; $limits = [ - 'tinyint' => 4, - 'smallint' => 6, - 'mediumint' => 8, - 'int' => 11, - 'bigint' => 20, + 'tinyint' => static::INT_DISPLAY_TINY, + 'smallint' => static::INT_DISPLAY_SMALL, + 'mediumint' => static::INT_DISPLAY_MEDIUM, + 'int' => static::INT_DISPLAY_REGULAR, + 'bigint' => static::INT_DISPLAY_BIG, ]; foreach ($sizes as $name => $length) { if ($limit >= $length) { @@ -1061,7 +1088,7 @@ public function getSqlType($type, ?int $limit = null): array } } } elseif (!$limit) { - $limit = 11; + $limit = static::INT_DISPLAY_REGULAR; } return ['name' => 'int', 'limit' => $limit]; @@ -1126,26 +1153,17 @@ public function getPhinxType($sqlTypeDef) break; case 'tinyint': $type = static::PHINX_TYPE_TINY_INTEGER; - $limit = static::INT_TINY; break; case 'smallint': $type = static::PHINX_TYPE_SMALL_INTEGER; - $limit = static::INT_SMALL; break; case 'mediumint': $type = static::PHINX_TYPE_MEDIUM_INTEGER; - $limit = static::INT_MEDIUM; break; case 'int': $type = static::PHINX_TYPE_INTEGER; - if ($limit === 11) { - $limit = null; - } break; case 'bigint': - if ($limit === 20) { - $limit = null; - } $type = static::PHINX_TYPE_BIG_INTEGER; break; case 'bit': diff --git a/src/Phinx/Db/Adapter/PostgresAdapter.php b/src/Phinx/Db/Adapter/PostgresAdapter.php index 18094e6ba..e220a53ed 100644 --- a/src/Phinx/Db/Adapter/PostgresAdapter.php +++ b/src/Phinx/Db/Adapter/PostgresAdapter.php @@ -35,6 +35,8 @@ class PostgresAdapter extends PdoAdapter self::PHINX_TYPE_BINARYUUID, ]; + private const GIN_INDEX_TYPE = 'gin'; + /** * Columns with comments * @@ -78,6 +80,11 @@ public function connect(): void $driverOptions[PDO::ATTR_DEFAULT_FETCH_MODE] = constant('\PDO::FETCH_' . strtoupper($options['fetch_mode'])); } + // pass \PDO::ATTR_PERSISTENT to driver options instead of useless setting it after instantiation + if (isset($options['attr_persistent'])) { + $driverOptions[PDO::ATTR_PERSISTENT] = $options['attr_persistent']; + } + $db = $this->createPdoConnection($dsn, $options['user'] ?? null, $options['pass'] ?? null, $driverOptions); try { @@ -1270,8 +1277,15 @@ protected function getIndexSqlDefinition(Index $index, string $tableName): strin $includedColumns = $index->getInclude() ? sprintf('INCLUDE ("%s")', implode('","', $index->getInclude())) : ''; + $createIndexSentence = 'CREATE %s INDEX %s ON %s '; + if ($index->getType() === self::GIN_INDEX_TYPE) { + $createIndexSentence .= ' USING ' . $index->getType() . '(%s) %s;'; + } else { + $createIndexSentence .= '(%s) %s;'; + } + return sprintf( - 'CREATE %s INDEX %s ON %s (%s) %s;', + $createIndexSentence, ($index->getType() === Index::UNIQUE ? 'UNIQUE' : ''), $this->quoteColumnName($indexName), $this->quoteTableName($tableName), diff --git a/src/Phinx/Db/Adapter/SQLiteAdapter.php b/src/Phinx/Db/Adapter/SQLiteAdapter.php index 8a9a6702a..154ce47ae 100644 --- a/src/Phinx/Db/Adapter/SQLiteAdapter.php +++ b/src/Phinx/Db/Adapter/SQLiteAdapter.php @@ -155,11 +155,26 @@ public function connect(): void $options = $this->getOptions(); - // use a memory database if the option was specified - if (!empty($options['memory']) || $options['name'] === static::MEMORY) { - $dsn = 'sqlite:' . static::MEMORY; + if (PHP_VERSION_ID < 80100 && (!empty($options['mode']) || !empty($options['cache']))) { + throw new RuntimeException('SQLite URI support requires PHP 8.1.'); + } elseif ((!empty($options['mode']) || !empty($options['cache'])) && !empty($options['memory'])) { + throw new RuntimeException('Memory must not be set when cache or mode are.'); + } elseif (PHP_VERSION_ID >= 80100 && (!empty($options['mode']) || !empty($options['cache']))) { + $params = []; + if (!empty($options['cache'])) { + $params[] = 'cache=' . $options['cache']; + } + if (!empty($options['mode'])) { + $params[] = 'mode=' . $options['mode']; + } + $dsn = 'sqlite:file:' . ($options['name'] ?? '') . '?' . implode('&', $params); } else { - $dsn = 'sqlite:' . $options['name'] . $this->suffix; + // use a memory database if the option was specified + if (!empty($options['memory']) || $options['name'] === static::MEMORY) { + $dsn = 'sqlite:' . static::MEMORY; + } else { + $dsn = 'sqlite:' . $options['name'] . $this->suffix; + } } $driverOptions = []; @@ -169,6 +184,11 @@ public function connect(): void $driverOptions[PDO::ATTR_DEFAULT_FETCH_MODE] = constant('\PDO::FETCH_' . strtoupper($options['fetch_mode'])); } + // pass \PDO::ATTR_PERSISTENT to driver options instead of useless setting it after instantiation + if (isset($options['attr_persistent'])) { + $driverOptions[PDO::ATTR_PERSISTENT] = $options['attr_persistent']; + } + $db = $this->createPdoConnection($dsn, null, null, $driverOptions); $this->setConnection($db); @@ -734,6 +754,21 @@ protected function getDeclaringSql(string $tableName): string } } + $columnsInfo = $this->getTableInfo($tableName); + + foreach ($columnsInfo as $column) { + $columnName = $column['name']; + $columnNamePattern = "\"$columnName\"|`$columnName`|\\[$columnName\\]|$columnName"; + $columnNamePattern = "#([\(,]+\\s*)($columnNamePattern)(\\s)#iU"; + + $sql = preg_replace($columnNamePattern, "$1`$columnName`$3", $sql); + } + + $tableNamePattern = "\"$tableName\"|`$tableName`|\\[$tableName\\]|$tableName"; + $tableNamePattern = "#^(CREATE TABLE)\s*($tableNamePattern)\s*(\()#Ui"; + + $sql = preg_replace($tableNamePattern, "$1 `$tableName` $3", $sql, 1); + return $sql; } diff --git a/src/Phinx/Db/Adapter/SqlServerAdapter.php b/src/Phinx/Db/Adapter/SqlServerAdapter.php index 1a022a8ba..7565aa045 100644 --- a/src/Phinx/Db/Adapter/SqlServerAdapter.php +++ b/src/Phinx/Db/Adapter/SqlServerAdapter.php @@ -77,6 +77,14 @@ public function connect(): void } $dsn .= ';database=' . $options['name'] . ';MultipleActiveResultSets=false'; + // option to add additional connection options + // https://docs.microsoft.com/en-us/sql/connect/php/connection-options?view=sql-server-ver15 + if (isset($options['dsn_options'])) { + foreach ($options['dsn_options'] as $key => $option) { + $dsn .= ';' . $key . '=' . $option; + } + } + $driverOptions = []; // charset support @@ -89,6 +97,9 @@ public function connect(): void $driverOptions[PDO::ATTR_DEFAULT_FETCH_MODE] = constant('\PDO::FETCH_' . strtoupper($options['fetch_mode'])); } + // Note, the PDO::ATTR_PERSISTENT attribute is not supported for sqlsrv and will throw an error when used + // See https://github.com/Microsoft/msphpsql/issues/65 + // support arbitrary \PDO::SQLSRV_ATTR_* driver options and pass them to PDO // http://php.net/manual/en/ref.pdo-sqlsrv.php#pdo-sqlsrv.constants foreach ($options as $key => $option) { diff --git a/src/Phinx/Db/Table.php b/src/Phinx/Db/Table.php index 2445eb548..4e0a638a6 100644 --- a/src/Phinx/Db/Table.php +++ b/src/Phinx/Db/Table.php @@ -380,7 +380,7 @@ public function hasColumn(string $columnName): bool /** * Add an index to a database table. * - * In $options you can specific unique = true/false or name (index name). + * In $options you can specify unique = true/false, and name (index name). * * @param string|array|\Phinx\Db\Table\Index $columns Table Column(s) * @param array $options Index Options diff --git a/src/Phinx/Migration/Manager.php b/src/Phinx/Migration/Manager.php index 69f3d8b15..d1e735536 100644 --- a/src/Phinx/Migration/Manager.php +++ b/src/Phinx/Migration/Manager.php @@ -63,6 +63,11 @@ class Manager */ protected $container; + /** + * @var int + */ + private $verbosityLevel = OutputInterface::OUTPUT_NORMAL | OutputInterface::VERBOSITY_NORMAL; + /** * @param \Phinx\Config\ConfigInterface $config Configuration Object * @param \Symfony\Component\Console\Input\InputInterface $input Console Input @@ -100,7 +105,7 @@ public function printStatus(string $environment, ?string $format = null): array if (count($migrations)) { // rewrite using Symfony Table Helper as we already have this library // included and it will fix formatting issues (e.g drawing the lines) - $output->writeln(''); + $output->writeln('', $this->verbosityLevel); switch ($this->getConfig()->getVersionOrder()) { case Config::VERSION_ORDER_CREATION_TIME: @@ -113,8 +118,8 @@ public function printStatus(string $environment, ?string $format = null): array throw new RuntimeException('Invalid version_order configuration option'); } - $output->writeln(" Status $migrationIdAndStartedHeader Finished Migration Name "); - $output->writeln('----------------------------------------------------------------------------------'); + $output->writeln(" Status $migrationIdAndStartedHeader Finished Migration Name ", $this->verbosityLevel); + $output->writeln('----------------------------------------------------------------------------------', $this->verbosityLevel); $env = $this->getEnvironment($environment); $versions = $env->getVersionLog(); @@ -189,17 +194,20 @@ public function printStatus(string $environment, ?string $format = null): array } $maxNameLength = max($maxNameLength, strlen($migration->getName())); - $output->writeln(sprintf( - '%s %14.0f %19s %19s %s', - $status, - $migration->getVersion(), - ($version ? $version['start_time'] : ''), - ($version ? $version['end_time'] : ''), - $migration->getName() - )); + $output->writeln( + sprintf( + '%s %14.0f %19s %19s %s', + $status, + $migration->getVersion(), + ($version ? $version['start_time'] : ''), + ($version ? $version['end_time'] : ''), + $migration->getName() + ), + $this->verbosityLevel + ); if ($version && $version['breakpoint']) { - $output->writeln(' BREAKPOINT SET'); + $output->writeln(' BREAKPOINT SET', $this->verbosityLevel); } $finalMigrations[] = ['migration_status' => trim(strip_tags($status)), 'migration_id' => sprintf('%14.0f', $migration->getVersion()), 'migration_name' => $migration->getName()]; @@ -214,12 +222,12 @@ public function printStatus(string $environment, ?string $format = null): array } } else { // there are no migrations - $output->writeln(''); - $output->writeln('There are no available migrations. Try creating one using the create command.'); + $output->writeln('', $this->verbosityLevel); + $output->writeln('There are no available migrations. Try creating one using the create command.', $this->verbosityLevel); } // write an empty line - $output->writeln(''); + $output->writeln('', $this->verbosityLevel); if ($format !== null) { switch ($format) { @@ -287,7 +295,7 @@ public function migrateToDateTime(string $environment, DateTime $dateTime, bool if (count($outstandingMigrations) > 0) { $migration = max($outstandingMigrations); - $this->getOutput()->writeln('Migrating to version ' . $migration); + $this->getOutput()->writeln('Migrating to version ' . $migration, $this->verbosityLevel); $this->migrate($environment, $migration, $fake); } } @@ -364,7 +372,7 @@ public function migrate(string $environment, ?int $version = null, bool $fake = */ public function executeMigration(string $name, MigrationInterface $migration, string $direction = MigrationInterface::UP, bool $fake = false): void { - $this->getOutput()->writeln(''); + $this->getOutput()->writeln('', $this->verbosityLevel); // Skip the migration if it should not be executed if (!$migration->shouldExecute()) { @@ -396,7 +404,7 @@ public function executeMigration(string $name, MigrationInterface $migration, st */ public function executeSeed(string $name, SeedInterface $seed): void { - $this->getOutput()->writeln(''); + $this->getOutput()->writeln('', $this->verbosityLevel); // Skip the seed if it should not be executed if (!$seed->shouldExecute()) { @@ -466,7 +474,8 @@ protected function printStatusOutput(string $name, string $status, ?string $dura $this->getOutput()->writeln( ' ==' . ' ' . $name . ':' . - ' ' . $status . ' ' . $duration . '' + ' ' . $status . ' ' . $duration . '', + $this->verbosityLevel ); } @@ -1118,4 +1127,15 @@ public function unsetBreakpoint(string $environment, ?int $version): void { $this->markBreakpoint($environment, $version, self::BREAKPOINT_UNSET); } + + /** + * @param int $verbosityLevel Verbosity level for info messages + * @return $this + */ + public function setVerbosityLevel(int $verbosityLevel) + { + $this->verbosityLevel = $verbosityLevel; + + return $this; + } } diff --git a/src/Phinx/Wrapper/TextWrapper.php b/src/Phinx/Wrapper/TextWrapper.php index 5fec31df2..62b7f2d8a 100644 --- a/src/Phinx/Wrapper/TextWrapper.php +++ b/src/Phinx/Wrapper/TextWrapper.php @@ -73,7 +73,7 @@ public function getExitCode(): int public function getStatus(?string $env = null): string { $command = ['status']; - if ($env ?: $this->hasOption('environment')) { + if ($this->hasEnvValue($env)) { $command['-e'] = $env ?: $this->getOption('environment'); } if ($this->hasOption('configuration')) { @@ -89,6 +89,15 @@ public function getStatus(?string $env = null): string return $this->executeRun($command); } + /** + * @param string|null $env environment name + * @return bool + */ + private function hasEnvValue($env): bool + { + return $env || $this->hasOption('environment'); + } + /** * Returns the output from running the "migrate" command. * @@ -99,7 +108,7 @@ public function getStatus(?string $env = null): string public function getMigrate(?string $env = null, ?string $target = null): string { $command = ['migrate']; - if ($env ?: $this->hasOption('environment')) { + if ($this->hasEnvValue($env)) { $command += ['-e' => $env ?: $this->getOption('environment')]; } if ($this->hasOption('configuration')) { @@ -126,7 +135,7 @@ public function getMigrate(?string $env = null, ?string $target = null): string public function getSeed(?string $env = null, ?string $target = null, $seed = null): string { $command = ['seed:run']; - if ($env ?: $this->hasOption('environment')) { + if ($this->hasEnvValue($env)) { $command += ['-e' => $env ?: $this->getOption('environment')]; } if ($this->hasOption('configuration')) { @@ -156,7 +165,7 @@ public function getSeed(?string $env = null, ?string $target = null, $seed = nul public function getRollback(?string $env = null, $target = null): string { $command = ['rollback']; - if ($env ?: $this->hasOption('environment')) { + if ($this->hasEnvValue($env)) { $command += ['-e' => $env ?: $this->getOption('environment')]; } if ($this->hasOption('configuration')) { diff --git a/tests/Phinx/Console/Output/RawBufferedOutput.php b/tests/Phinx/Console/Output/RawBufferedOutput.php index 886a460b0..b8d1e2573 100644 --- a/tests/Phinx/Console/Output/RawBufferedOutput.php +++ b/tests/Phinx/Console/Output/RawBufferedOutput.php @@ -13,8 +13,8 @@ class RawBufferedOutput extends \Symfony\Component\Console\Output\BufferedOutput * @param int $options * @return void */ - public function writeln($messages, $options = self::OUTPUT_RAW) + public function writeln($messages, $options = 0) { - $this->write($messages, true, $options); + $this->write($messages, true, $options | self::OUTPUT_RAW); } } diff --git a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php index 623af44d2..e6b0e1c44 100644 --- a/tests/Phinx/Db/Adapter/MysqlAdapterTest.php +++ b/tests/Phinx/Db/Adapter/MysqlAdapterTest.php @@ -884,6 +884,47 @@ public function testChangeColumnDefaultToNull() $this->assertNull($rows[1]['Default']); } + public function sqlTypeIntConversionProvider() + { + return [ + // tinyint + [AdapterInterface::PHINX_TYPE_TINY_INTEGER, null, 'tinyint', 4], + [AdapterInterface::PHINX_TYPE_TINY_INTEGER, 2, 'tinyint', 2], + [AdapterInterface::PHINX_TYPE_TINY_INTEGER, MysqlAdapter::INT_TINY, 'tinyint', 4], + // smallint + [AdapterInterface::PHINX_TYPE_SMALL_INTEGER, null, 'smallint', 6], + [AdapterInterface::PHINX_TYPE_SMALL_INTEGER, 3, 'smallint', 3], + [AdapterInterface::PHINX_TYPE_SMALL_INTEGER, MysqlAdapter::INT_SMALL, 'smallint', 6], + // medium + [AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, null, 'mediumint', 8], + [AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, 2, 'mediumint', 2], + [AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, MysqlAdapter::INT_MEDIUM, 'mediumint', 8], + // integer + [AdapterInterface::PHINX_TYPE_INTEGER, null, 'int', 11], + [AdapterInterface::PHINX_TYPE_INTEGER, 4, 'int', 4], + [AdapterInterface::PHINX_TYPE_INTEGER, MysqlAdapter::INT_TINY, 'tinyint', 4], + [AdapterInterface::PHINX_TYPE_INTEGER, MysqlAdapter::INT_SMALL, 'smallint', 6], + [AdapterInterface::PHINX_TYPE_INTEGER, MysqlAdapter::INT_MEDIUM, 'mediumint', 8], + [AdapterInterface::PHINX_TYPE_INTEGER, MysqlAdapter::INT_REGULAR, 'int', 11], + [AdapterInterface::PHINX_TYPE_INTEGER, MysqlAdapter::INT_BIG, 'bigint', 20], + // bigint + [AdapterInterface::PHINX_TYPE_BIG_INTEGER, null, 'bigint', 20], + [AdapterInterface::PHINX_TYPE_BIG_INTEGER, 4, 'bigint', 4], + [AdapterInterface::PHINX_TYPE_BIG_INTEGER, MysqlAdapter::INT_BIG, 'bigint', 20], + ]; + } + + /** + * @dataProvider sqlTypeIntConversionProvider + * The second argument is not typed as MysqlAdapter::INT_BIG is a float, and all other values are integers + */ + public function testGetSqlTypeIntegerConversion(string $type, $limit, string $expectedType, int $expectedLimit) + { + $sqlType = $this->adapter->getSqlType($type, $limit); + $this->assertSame($expectedType, $sqlType['name']); + $this->assertSame($expectedLimit, $sqlType['limit']); + } + public function testLongTextColumn() { $table = new \Phinx\Db\Table('t', [], $this->adapter); @@ -2165,4 +2206,55 @@ public function testInvalidPdoAttribute($attribute) $this->expectExceptionMessage('Invalid PDO attribute: ' . $attribute . ' (\PDO::' . strtoupper($attribute) . ')'); $adapter->connect(); } + + public function integerDataTypesSQLProvider() + { + return [ + // Types without a width should always have a null limit + ['bigint', ['name' => AdapterInterface::PHINX_TYPE_BIG_INTEGER, 'limit' => null, 'scale' => null]], + ['int', ['name' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => null, 'scale' => null]], + ['mediumint', ['name' => AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, 'limit' => null, 'scale' => null]], + ['smallint', ['name' => AdapterInterface::PHINX_TYPE_SMALL_INTEGER, 'limit' => null, 'scale' => null]], + ['tinyint', ['name' => AdapterInterface::PHINX_TYPE_TINY_INTEGER, 'limit' => null, 'scale' => null]], + + // Types which include a width should always have that as their limit + ['bigint(20)', ['name' => AdapterInterface::PHINX_TYPE_BIG_INTEGER, 'limit' => 20, 'scale' => null]], + ['bigint(10)', ['name' => AdapterInterface::PHINX_TYPE_BIG_INTEGER, 'limit' => 10, 'scale' => null]], + ['bigint(1) unsigned', ['name' => AdapterInterface::PHINX_TYPE_BIG_INTEGER, 'limit' => 1, 'scale' => null]], + ['int(11)', ['name' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => 11, 'scale' => null]], + ['int(10) unsigned', ['name' => AdapterInterface::PHINX_TYPE_INTEGER, 'limit' => 10, 'scale' => null]], + ['mediumint(6)', ['name' => AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, 'limit' => 6, 'scale' => null]], + ['mediumint(8) unsigned', ['name' => AdapterInterface::PHINX_TYPE_MEDIUM_INTEGER, 'limit' => 8, 'scale' => null]], + ['smallint(2)', ['name' => AdapterInterface::PHINX_TYPE_SMALL_INTEGER, 'limit' => 2, 'scale' => null]], + ['smallint(5) unsigned', ['name' => AdapterInterface::PHINX_TYPE_SMALL_INTEGER, 'limit' => 5, 'scale' => null]], + ['tinyint(3) unsigned', ['name' => AdapterInterface::PHINX_TYPE_TINY_INTEGER, 'limit' => 3, 'scale' => null]], + ['tinyint(4)', ['name' => AdapterInterface::PHINX_TYPE_TINY_INTEGER, 'limit' => 4, 'scale' => null]], + + // Special case for commonly used boolean type + ['tinyint(1)', ['name' => AdapterInterface::PHINX_TYPE_BOOLEAN, 'limit' => null, 'scale' => null]], + ]; + } + + /** + * @dataProvider integerDataTypesSQLProvider + */ + public function testGetPhinxTypeFromSQLDefinition(string $sqlDefinition, array $expectedResponse) + { + $result = $this->adapter->getPhinxType($sqlDefinition); + + $this->assertSame($expectedResponse['name'], $result['name'], "Type mismatch - got '{$result['name']}' when expecting '{$expectedResponse['name']}'"); + $this->assertSame($expectedResponse['limit'], $result['limit'], "Field upper boundary mismatch - got '{$result['limit']}' when expecting '{$expectedResponse['limit']}'"); + } + + public function testPdoPersistentConnection() + { + $adapter = new MysqlAdapter(MYSQL_DB_CONFIG + ['attr_persistent' => true]); + $this->assertTrue($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } + + public function testPdoNotPersistentConnection() + { + $adapter = new MysqlAdapter(MYSQL_DB_CONFIG); + $this->assertFalse($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } } diff --git a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php index ab0cf1088..99c2502a1 100644 --- a/tests/Phinx/Db/Adapter/PostgresAdapterTest.php +++ b/tests/Phinx/Db/Adapter/PostgresAdapterTest.php @@ -352,6 +352,16 @@ public function testCreateTableWithUniqueIndexes() $this->assertFalse($this->adapter->hasIndex('table1', ['email', 'user_email'])); } + public function testCreateTableWithFullTextSearchIndexes() + { + $table = new \Phinx\Db\Table('table1', [], $this->adapter); + $table->addColumn('names', 'jsonb') + ->addIndex('names', ['type' => 'gin']) + ->save(); + + $this->assertTrue($this->adapter->hasIndex('table1', ['names'])); + } + public function testCreateTableWithNamedIndexes() { $table = new \Phinx\Db\Table('table1', [], $this->adapter); @@ -2355,4 +2365,16 @@ public function testInvalidPdoAttribute() $this->expectExceptionMessage('Invalid PDO attribute: attr_invalid (\PDO::ATTR_INVALID)'); $adapter->connect(); } + + public function testPdoPersistentConnection() + { + $adapter = new PostgresAdapter(PGSQL_DB_CONFIG + ['attr_persistent' => true]); + $this->assertTrue($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } + + public function testPdoNotPersistentConnection() + { + $adapter = new PostgresAdapter(PGSQL_DB_CONFIG); + $this->assertFalse($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } } diff --git a/tests/Phinx/Db/Adapter/SQLiteAdapterTest.php b/tests/Phinx/Db/Adapter/SQLiteAdapterTest.php index 58313c783..6baaa7a6f 100644 --- a/tests/Phinx/Db/Adapter/SQLiteAdapterTest.php +++ b/tests/Phinx/Db/Adapter/SQLiteAdapterTest.php @@ -488,6 +488,33 @@ public function testAddColumnWithDefaultEmptyString() $this->assertEquals("''", $rows[1]['dflt_value']); } + public function irregularCreateTableProvider() + { + return [ + ["CREATE TABLE \"users\"\n( `id` INTEGER NOT NULL )", ['id', 'foo']], + ['CREATE TABLE users ( id INTEGER NOT NULL )', ['id', 'foo']], + ["CREATE TABLE [users]\n(\nid INTEGER NOT NULL)", ['id', 'foo']], + ["CREATE TABLE \"users\" ([id] \n INTEGER NOT NULL\n, \"bar\" INTEGER)", ['id', 'bar', 'foo']], + ]; + } + + /** + * @dataProvider irregularCreateTableProvider + */ + public function testAddColumnToIrregularCreateTableStatements(string $createTableSql, array $expectedColumns): void + { + $this->adapter->execute($createTableSql); + $table = new \Phinx\Db\Table('users', [], $this->adapter); + $table->addColumn('foo', 'string'); + $table->update(); + + $columns = $this->adapter->getColumns('users'); + $columnCount = count($columns); + for ($i = 0; $i < $columnCount; $i++) { + $this->assertEquals($expectedColumns[$i], $columns[$i]->getName()); + } + } + public function testAddDoubleColumn() { $table = new \Phinx\Db\Table('table1', [], $this->adapter); @@ -2310,4 +2337,16 @@ public function testPdoExceptionUpdateNonExistingTable() $table = new \Phinx\Db\Table('non_existing_table', [], $this->adapter); $table->addColumn('column', 'string')->update(); } + + public function testPdoPersistentConnection() + { + $adapter = new SQLiteAdapter(SQLITE_DB_CONFIG + ['attr_persistent' => true]); + $this->assertTrue($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } + + public function testPdoNotPersistentConnection() + { + $adapter = new SQLiteAdapter(SQLITE_DB_CONFIG); + $this->assertFalse($adapter->getConnection()->getAttribute(\PDO::ATTR_PERSISTENT)); + } } diff --git a/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php b/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php index fce5563c4..f01d185ea 100644 --- a/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php +++ b/tests/Phinx/Db/Adapter/SqlServerAdapterTest.php @@ -50,6 +50,14 @@ public function testConnection() $this->assertSame(\PDO::ERRMODE_EXCEPTION, $this->adapter->getConnection()->getAttribute(\PDO::ATTR_ERRMODE)); } + public function testConnectionWithDsnOptions() + { + $options = $this->adapter->getOptions(); + $options['dsn_options'] = ['TrustServerCertificate' => 'true']; + $this->adapter->setOptions($options); + $this->assertInstanceOf('PDO', $this->adapter->getConnection()); + } + public function testConnectionWithFetchMode() { $options = $this->adapter->getOptions(); diff --git a/tests/Phinx/Wrapper/TextWrapperTest.php b/tests/Phinx/Wrapper/TextWrapperTest.php new file mode 100644 index 000000000..13203c915 --- /dev/null +++ b/tests/Phinx/Wrapper/TextWrapperTest.php @@ -0,0 +1,58 @@ +createMock(PhinxApplication::class); + $app + ->expects($this->once()) + ->method('doRun') + ->with(new ArrayInput($expectedCommand)) + ->willReturn(0); + + $wrapper = new TextWrapper($app, $options); + + $wrapper->getStatus($env); + } + + public function envValueProvider(): array + { + return [ + 'env-value-only' => [ + self::ANY_ENV_VALUE, + [], + ['status', '-e' => self::ANY_ENV_VALUE], + ], + 'options-env-value-only' => [ + null, + ['environment' => self::ANY_ENV_VALUE], + ['status', '-e' => self::ANY_ENV_VALUE], + ], + 'both-values' => [ + self::ANY_ENV_VALUE, + ['environment' => self::ANY_ENV_VALUE . 'additional'], + ['status', '-e' => self::ANY_ENV_VALUE], + ], + 'no-values' => [ + null, + [], + ['status'], + ], + ]; + } +}