Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to use $params in anonymous functions? #31

Closed
razonyang opened this issue May 29, 2019 · 9 comments
Closed

Is it possible to use $params in anonymous functions? #31

razonyang opened this issue May 29, 2019 · 9 comments

Comments

@razonyang
Copy link

razonyang commented May 29, 2019

Composer.json

    "extra": {
        "config-plugin": {
            "params": [
                "config/params.php",
                "?config/params-local.php"
            ],
            "web": [
                "config/web.php"
            ]
        }
    }

params.php

return [
    'app.name' => 'My Application',
];

web.php

return [
    'app' => function () use($params) {
        return [
            'name' => $params['app.name']
        ];
    },
    'appName' => $params['app.name'],
];

index.php

require __DIR__.'/../vendor/autoload.php';

$config = require hiqdev\composer\config\Builder::path('web');

$appClosure = $config['app'];
$app = call_user_func($appClosure);
var_dump($app, $config['appName']);

Got:

php ./public/index.php
PHP Notice: Undefined variable: params in /home/razon/Projects/php/composer-config/vendor/hiqdev/composer-config-plugin-output/web.php on line 10
array(1) {
["name"]=>
NULL
}
string(14) "My Application"

BTW, the generated web.php missing use language structure

$baseDir = dirname(dirname(dirname(__DIR__)));

defined('COMPOSER_CONFIG_PLUGIN_BASEDIR') or define('COMPOSER_CONFIG_PLUGIN_BASEDIR', $baseDir);

$_ENV = array_merge((array) require __DIR__ . '/dotenv.php', (array) $_ENV);

return array (
  'app' => function () {
        return [
            'name' => $params['app.name']
        ];
    },
  'appName' => 'My Application',
);
@hiqsol
Copy link
Member

hiqsol commented May 29, 2019

Please, show what do you want in practice, cause your example doesn't look practical.

@razonyang
Copy link
Author

razonyang commented May 29, 2019

I am trying to access parameters in an anonymous function.

Such as logger configuration(DI), I want to make FileTarget's levels to be mergeable via params.php and params-local.php:

    'logger' => function (yii\di\Container $container) {
        $logger = new Yiisoft\Log\Logger([
            $container->get(Yiisoft\Log\FileTarget::class),
        ]);

        return $logger;
    },
    Yiisoft\Log\FileTarget::class => function (yii\di\Container $container) use($params) {
        /** @var yii\base\Aliases $aliases */
        $aliases = $container->get('aliases');
        $target = new Yiisoft\Log\FileTarget(
            $aliases->get($params['console.logger.target.file.logFile']),
            $container->get(Yiisoft\Log\FileRotator::class)
        );
        $target->levels = $params['logger.target.file.levels'];
        //...
        return $target;
    },
    Yiisoft\Log\FileRotator::class => [
        '__class' => Yiisoft\Log\FileRotator::class,
    ],

params.php

return [
    'logger.target.file.levels' => ['warning', 'error'],
];

params-local.php

return [
    'logger.target.file.levels' => ['info', 'debug'],
];

@hiqsol
Copy link
Member

hiqsol commented May 29, 2019

You can get params from the app object similarly you get aliases:

$target->levels = $container->get('app')->params['logger.target.file.levels'];

But it looks like a good case to improve Yii DI for these objects could be configured with arrays only without closures.

Something like this:

    'logger' => [
        '__class' => Logger::class,
        '__construct' => [
            [Reference::to('file-target')],
        ],
    ],
    'file-target' => [
        '__class' => Yiisoft\Log\FileTarget::class,
        '__construct' => [
            Reference::aliasTo('@logger/logFile'),
            Reference::to(Yiisoft\Log\FileRotator::class),
        ],
        'levels' => $params['logger.target.file.levels'],
    ],

I'll look into it on a weekend.

@razonyang
Copy link
Author

razonyang commented May 29, 2019

Your solution look good to me:)

EDIT:
I could not find the method Reference::aliasTo(yiisoft/di), am I missing something?

@razonyang
Copy link
Author

Hi, I found another issue about exporting Closure, here is an example of yii-demo.

I've read the code of Helper::dumpClosure, but have no idea how to handle it so far.

It may can be fixed by two ways:

  1. Defines full qualified name in closure, such as return new Yiisoft\Log\Logger([]), simple, but strange.
  2. Dump the use lines.

Reproduce:

$ ./vendor/bin/yii serve
$ curl http://localhost:8080
[Tue Jul  2 13:52:29 2019] PHP Fatal error:  Uncaught Error: Class 'Logger' not found in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php:478
Stack trace:
#0 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/CallableDefinition.php(19): {closure}(Object(yii\di\Container), Array)
#1 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\CallableDefinition->resolve(Object(yii\di\Container), Array)
#2 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(116): yii\di\Container->buildInternal('logger', Array)
#3 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(84): yii\di\Container->build('logger', Array)
#4 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/Reference.php(45): yii\di\Container->get('logger')
#5 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\Reference->resolve(Object(yii\di\Container), Array)
# in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php on line 478
[Tue Jul  2 13:52:29 2019] [::1]:48260 [500]: / - Uncaught Error: Class 'Logger' not found in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php:478
Stack trace:
#0 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/CallableDefinition.php(19): {closure}(Object(yii\di\Container), Array)
#1 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\CallableDefinition->resolve(Object(yii\di\Container), Array)
#2 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(116): yii\di\Container->buildInternal('logger', Array)
#3 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(84): yii\di\Container->build('logger', Array)
#4 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/factory/src/Definitions/Reference.php(45): yii\di\Container->get('logger')
#5 /home/razon/Projects/yiisoft/yii-demo/vendor/yiisoft/di/src/Container.php(128): Yiisoft\Factory\Definitions\Reference->resolve(Object(yii\di\Container), Array)
# in /home/razon/Projects/yiisoft/yii-demo/vendor/hiqdev/composer-config-plugin-output/web.php on line 478

@hiqsol
Copy link
Member

hiqsol commented Jul 2, 2019

Dump the use lines is good but how? :)

@razonyang
Copy link
Author

I have no idea so far, it maybe impossible :(

@samdark
Copy link
Contributor

samdark commented Jul 31, 2019

That's actually a problem not about anonymous functions but about $params is not defined in configs at all.

@hiqsol
Copy link
Member

hiqsol commented Jul 31, 2019

Initialization of $params was added in configs.
So this problem is fixed. Just use as you expected from the very beginning:

In web.php:

return [
    'app' => function () use ($params) {
        return [
            'name' => $params['app.name']
        ];
    },
    'appName' => $params['app.name'],
];

Closing this issue. Please open a new one in case of any problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants