bizley / yii2-migration

Yii 2 Migration Creator And Updater
Apache License 2.0
288 stars 36 forks source link

[Bug] Path aliasing error encountered when generating migration #107

Closed SilverPreece closed 4 years ago

SilverPreece commented 4 years ago

Describe the bug When attempting to create an initial migration for a database (no other migrations currently exist in this project), the migration generator immediately fails with the error:

 > Generating migration for creating table 'category' ...ERROR!
 > Invalid path alias: @bizley/migration/views/migration.php

Expected behavior Expected that a migration file would be created without error.

Additional context Full console output:

root@e62163c92528:/application# ./yii migration/create "*"
Yii 2 Migration Generator Tool v4.0.5
 > Are you sure you want to generate migrations for the following tables?
   - category
   - collection
   - item
   - item_category_link
   - item_collection_link
   - item_template (yes|no) [no]:yes 

 > Generating migration for creating table 'category' ...ERROR!
 > Invalid path alias: @bizley/migration/views/migration.php
root@e62163c92528:/application#

Current contents of console config file:

<?php

$params = require_once(__DIR__ . '/params.php');
$dbconfig = require_once(__DIR__ . '/db.php');

return [
    'id' => 'magpie-console',
    'basePath' => dirname(__DIR__),
    'controllerNamespace' => 'Magpie\Command',
    'controllerMap' => [
        'migration' => [
            'class' => 'bizley\migration\controllers\MigrationController',
        ]
    ],
    'aliases' => [
        '@app' => dirname(__DIR__),
        '@Magpie' => dirname(__DIR__),
    ],
    'components' => [
        'db' => $dbconfig
    ]
];

Affected versions Yii: 2.0.35 yii2-migration: 4.0.5 PHP version: 7.4.7 PostgreSQL version: 11.1

Environment is dockerised.

Workaround

Given that this was simply a missing path alias, I was able to look up in your unit tests where the alias should point, and define it in my console configuration file:

    'aliases' => [
        '@app' => dirname(__DIR__),
        '@bizley/migration' => dirname(__DIR__, 2) . '/vendor/bizley/migration/src',
        '@Magpie' => dirname(__DIR__),
    ],

I couldn't see anything about having to define this in the introductory documentation, so I'm not 100% if you would consider this a software bug or missing documentation, but it feels a bit fragile to me to be defining path aliases into the /vendor folder.

With the alias in place in my configuration file, the migrations were created as expected. Very nice, thank you for the library!

bizley commented 4 years ago

That is really weird and not supposed to happen. Usually this alias is created automatically through yii2-composer. Are you by any chance using Composer v2?

SilverPreece commented 4 years ago

Ah, I neglected to include my Composer version. Composer reports:

Composer 1.10.1 2020-03-13 20:34:27

I'm not using a project template to make this particular app as I'm trying to keep things minimal, but I know that yii2-composer is a direct dependency of Yii2 itself, and I can see it installed in my /vendor folder.

Do you know if there is any additional configuration I would require in my composer.json file? I'm at a very early prototyping stage so far for this project, so there's very little in there.

bizley commented 4 years ago

Adding this to your composer.json should help with this package and all others:

"scripts": {
    "post-install-cmd": [
        "yii\\composer\\Installer::postInstall"
    ],
},

By default in Yii templates there is also section with post-create-project-cmd and extra but I think this will not be required in your case (but just in case I'm mentioning it).

bizley commented 4 years ago

Let me know if it works.

SilverPreece commented 4 years ago

No dice, unfortunately. I removed the alias I made, added the post-install hook in composer.json, deleted /vendor and reinstalled. The post-install hook showed logged that it was running in the Composer output, but I didn't see any difference in my files and encountered the same error when running migrations. Do you know where it tries to create the alias?

bizley commented 4 years ago

I tried to recreate that issue with minimal setup but everything works as expected and doesn't need any composer scripts. This is what I did:

  1. Create composer.json:
    {
    "require": {
    "yiisoft/yii2": "^2.0.35",
    "bizley/migration": "^4.0"
    },
    "replace": {
    "bower-asset/jquery": "*",
    "bower-asset/jquery.inputmask": "*",
    "bower-asset/inputmask": "*",
    "bower-asset/punycode": "*",
    "bower-asset/yii2-pjax": "*"
    }
    }
  2. Run composer install.
  3. Verify creating alias - run cat vendor/yiisoft/extensions.php - output:
    
    <?php

$vendorDir = dirname(DIR);

return array ( 'bizley/migration' => array ( 'name' => 'bizley/migration', 'version' => '4.0.5.0', 'alias' => array ( '@bizley/migration' => $vendorDir . '/bizley/migration/src', ), ), );

4. Create `yii` file:
```sh
#!/usr/bin/env php
<?php

defined('YII_DEBUG') or define('YII_DEBUG', true);
defined('YII_ENV') or define('YII_ENV', 'dev');

require __DIR__ . '/vendor/autoload.php';
require __DIR__ . '/vendor/yiisoft/yii2/Yii.php';

$application = new yii\console\Application(
[
    'id' => 'minimal',
    'basePath' => '.',
    'controllerMap' => [
        'migration' => [
            'class' => 'bizley\migration\controllers\MigrationController',
        ],
    ],
    'components' => [
        'db' => [
            'class' => \yii\db\Connection::class,
            'dsn' => 'sqlite:./test.db'
        ]
    ]
]
);
$exitCode = $application->run();
exit($exitCode);
  1. Run sqlite3 test.db:
    create table "test" (id integer);
    .quit
  2. Run yii migration/create test - output:

    Yii 2 Migration Generator Tool v4.0.5
    
    > Generating migration for creating table 'test' ...DONE!
    > Saved as '/home/bizley/git/test-min/migrations/m200630_074044_create_table_test.php'
    
    Generated 1 file
    (!) Remember to verify files before applying migration.

Ubuntu 20.04 / PHP 7.4.6

SilverPreece commented 4 years ago

This is very strange. I did another nuke + rebuild of my /vendor folder and there it is, sat happy in my /vendor/yiisoft/extensions.php file:

return array (
  'bizley/migration' => 
  array (
    'name' => 'bizley/migration',
    'version' => '4.0.5.0',
    'alias' => 
    array (
      '@bizley/migration' => $vendorDir . '/bizley/migration/src',
    ),
  ),

However, if I remove my redefinition of the alias and try the console command again, it doesn't work! I get the same error as before.

I'm currently trying to debug an issue with another extension that's somewhat similar - automatic configuration that isn't working. I'm starting to wonder if there's something up with my Yii setup, but there's so little in it so far! I'll look over it some more this evening.

SilverPreece commented 4 years ago

Aha! Success!

I managed to figure out that the extensions.php file was never executed. I realised that Yii was not correctly finding my /vendor folder. As the Composer autoloader was being correctly loaded and all classes appeared as normal, the lack of configuration was not immediately apparent. It seems that if Yii cannot load the extensions file, it fails silently.

The fix was simple, and I shall leave it here for others who may encounter this issue in future. I added the path to my /vendor folder as described in the Yii docs here: https://www.yiiframework.com/wiki/778/moving-the-vendor-directory-for-multiple-projects

return [
    'id' => 'app-console',
    'aliases' => [
        '@app' => dirname(__DIR__),
        '@Magpie' => dirname(__DIR__),
    ],
    'basePath' => dirname(__DIR__),

    // ....

    'vendorPath' => dirname(__DIR__, 2) . '/vendor'
];

That's what I get for making top-level src and test folders with my Composer file! Thanks for your assistance, sorry for the misunderstanding.

bizley commented 4 years ago

Great! Glad it all worked out :)