Hyper::$plugin must not be accessed before initialization
corneliusio opened this issue · 16 comments
Describe the bug
This appears to be the reintroduction of a bug that was resolved in #29, particularly in reference to this comment, #29 (comment).
After updating to Hyper 1.1.8, I get the following error across the entire dashboard. This does not happen in previous versions.
Error: Typed static property verbb\hyper\Hyper::$plugin must not be accessed before initialization in /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/verbb/hyper/src/fields/HyperField.php:397
Stack trace:
#0 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/base/Component.php(180): verbb\hyper\fields\HyperField->setLinkTypes(Array)
#1 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/BaseYii.php(558): yii\base\Component->__set('linkTypes', Array)
#2 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/base/BaseObject.php(107): yii\BaseYii::configure(Object(verbb\hyper\fields\HyperField), Array)
#3 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/base/Model.php(78): yii\base\BaseObject->__construct(Array)
#4 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/verbb/hyper/src/fields/HyperField.php(75): craft\base\Model->__construct(Array)
#5 [internal function]: verbb\hyper\fields\HyperField->__construct(Array)
#6 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/di/Container.php(419): ReflectionClass->newInstanceArgs(Array)
#7 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/di/Container.php(170): yii\di\Container->build('verbb\\hyper\\fie...', Array, Array)
#8 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/BaseYii.php(365): yii\di\Container->get('verbb\\hyper\\fie...', Array, Array)
#9 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/Craft.php(54): yii\BaseYii::createObject(Array, Array)
#10 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/helpers/Component.php(122): Craft::createObject(Array)
#11 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Fields.php(593): craft\helpers\Component::createComponent(Array, 'craft\\base\\Fiel...')
#12 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Fields.php(618): craft\services\Fields->createField(Array)
#13 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Fields.php(647): craft\services\Fields->_fields(NULL)
#14 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/elements/db/ElementQuery.php(2086): craft\services\Fields->getAllFields()
#15 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/elements/db/ElementQuery.php(1393): craft\elements\db\ElementQuery->customFields()
#16 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/db/QueryBuilder.php(227): craft\elements\db\ElementQuery->prepare(Object(craft\db\mysql\QueryBuilder))
#17 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/db/Query.php(157): yii\db\QueryBuilder->build(Object(craft\elements\db\UserQuery))
#18 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/db/Query.php(287): yii\db\Query->createCommand(Object(craft\db\Connection))
#19 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/db/Query.php(275): yii\db\Query->one(NULL)
#20 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/elements/db/ElementQuery.php(1590): craft\db\Query->one(NULL)
#21 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/elements/User.php(519): craft\elements\db\ElementQuery->one()
#22 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/web/User.php(698): craft\elements\User::findIdentity(1)
#23 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/web/User.php(500): yii\web\User->renewAuthStatus()
#24 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/web/User.php(199): craft\web\User->renewAuthStatus()
#25 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/base/Component.php(139): yii\web\User->getIdentity()
#26 /Users/cornelius/Git/@mostlyserious/coxhealth/config/environment-label.php(7): yii\base\Component->__get('identity')
#27 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Config.php(289): include('/Users/corneliu...')
#28 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Config.php(281): craft\services\Config->_configFromFileInternal('/Users/corneliu...')
#29 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Plugins.php(928): craft\services\Config->getConfigFromFile('environment-lab...')
#30 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Plugins.php(228): craft\services\Plugins->createPlugin('environment-lab...', Array)
#31 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/base/ApplicationTrait.php(1580): craft\services\Plugins->loadPlugins()
#32 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/web/Application.php(108): craft\web\Application->_postInit()
#33 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/base/BaseObject.php(109): craft\web\Application->init()
#34 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/base/Application.php(204): yii\base\BaseObject->__construct(Array)
#35 [internal function]: yii\base\Application->__construct(Array)
#36 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/di/Container.php(419): ReflectionClass->newInstanceArgs(Array)
#37 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/di/Container.php(170): yii\di\Container->build('craft\\web\\Appli...', Array, Array)
#38 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/yiisoft/yii2/BaseYii.php(365): yii\di\Container->get('craft\\web\\Appli...', Array, Array)
#39 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/Craft.php(54): yii\BaseYii::createObject(Array, Array)
#40 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/bootstrap/bootstrap.php(256): Craft::createObject(Array)
#41 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/bootstrap/web.php(40): require('/Users/corneliu...')
#42 /Users/cornelius/Git/@mostlyserious/coxhealth/web/index.php(11): require('/Users/corneliu...')
#43 /Users/cornelius/.composer/vendor/laravel/valet/server.php(235): require('/Users/corneliu...')
#44 {main}
Steps to reproduce
- For both of the sites I have this setup on (one very close to a fresh install) the only step is to upgrade to Hyper 1.1.8
Craft CMS version
4.4.14
Plugin version
1.1.8
Multi-site?
No
Additional context
No response
Can’t replicate this on a fresh install. Might have something to do with the environment-label
plugin?
#29 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Plugins.php(928): craft\services\Config->getConfigFromFile('environment-lab...')
#30 /Users/cornelius/Git/@mostlyserious/coxhealth/vendor/craftcms/cms/src/services/Plugins.php(228): craft\services\Plugins->createPlugin('environment-lab...', Array)
@engram-design Ah! So sorry, let me dig into that and make sure. Having run into the same error as before I may have jumped the gun.
@engram-design So not exactly. What specifically is causing the issue isn't the environment-label
plugin, but rather making a reference to Craft::$app->user->identity
in a config file. It seems that there shouldn't be any interference here between this early call to the current user and the plugin initialization.
Ah yes, I've run into other scenarios where that's happened. It's pretty much due to when you access an element (a User element in this case), Craft will have to parse all custom fields on that element, and to do that, it'll go through all registered fields, including Hyper. There's things we do on initialization of Hyper fields that has to be done, but it's being triggered at this early point before Craft is fully ready to deal with it.
Fixed this for the next release. To get this early run composer require verbb/hyper:"dev-craft-4 as 1.1.8"
That totally makes sense, thanks for the insight and the fix!
@engram-design Heads up, I installed dev-craft-4 as 1.1.8
to test the update and the error was fixed however, it wiped all of the field settings for Hyper fields. 😕
Not the biggest deal on my end as the site I tested it on is in very early dev, but wanted to call out.
Point of clarification, it looks like it may have only caused an issue with the front-end of the settings page and when I resaved the field THEN the settings were cleared. Looks like I have a few Hyper fields that didn't lose there settings.
My other thought here, is where are you calling your identity check, and what is it for? It might very well be because this line is called before Craft has initialized plugins it’s causing issues.
Maybe you could wrap your identity check (and any subsequent code) with the following check https://github.com/craftcms/generator/blob/main/src/generators/Plugin.php#L728-L732
(Sorry for the delay, was off work half the week for holiday here in US) Appreciate the recommendation! Unfortunately, because this check is being returned from a file in config/
there's not really any way to delay or wrap the check in a closure. That said, it does seem apparent that this has more to do with the order in which Craft initializes fields, plugins, and configuration than it does any fundamental issue here. While it would be a nice convenience to be able to do this, it's not a critical check and I can remove it all together.
I was just checking if you can wrap the call in the init method. I'm not sure what you're using the config for, but even if a function is supported, that could work.
Craft::$app->onInit(function() {
Craft::$app->user->identity
// ...
});
I did chat with @brandonkelly about this briefly, but it's pretty much the way that Craft handles its initialization. But I'm still looking into it...
So the situation is this: I'm using the Environment Label. Then in config/environment-label.php
I have the following:
<?php
use Craft;
use craft\helpers\App;
return [
'showLabel' => Craft::$app->user->identity->admin,
'labelText' => App::env('HTTP_HOST'),
'prefixText' => sprintf('%s | php@%s | ', App::env('CRAFT_ENVIRONMENT'), App::phpVersion()),
'labelColor' => App::env('CRAFT_ENVIRONMENT') !== 'production'
? (App::devMode() ? '#29333d' : '#facc15')
: '#10b981',
'textColor' => App::env('CRAFT_ENVIRONMENT') !== 'production'
? (App::devMode() ? '#facc15' : '#29333d')
: '#29333d'
];
The call is simply to either display or hide the env indicator depending on the user role. Because Craft expects these files to essentially statically export an array, there's no way to wrap this in the Craft::$app->onInit
method. I may check to see if I can overwrite this config's values within a Yii modules init method for the project, but doubt that will work. At the end of the day, I was doing this check just to keep the client's view a bit less cluttered as it's really only our agency's members that tend to jump between production and staging enough to worry about it, but I don't need this check. I can simply show the label all the time.
Frankly, I could just recreate the functionality of this plugin within our projects' boilerplate and handle the extra logic myself. So at the end of the day, we'll be fine if this conflict is simply not something that can be easily avoided on the part of this plugin.
Thanks for the clarification, and that makes sense. I'm keen to see if @brandonkelly has anything to say about this!
Environment Label’s showLabel
setting could be updated to support being set to a callable
, and that could be called the first time the setting is actually needed.
$showLabel = is_callable($this->settings->showLabel)
? call_user_func($this->settings->showLabel)
: $this->settings->showLabel;
Then the settings could be changed to:
return [
'showLabel' => fn() => Craft::$app->user->identity->admin,
// ...
@brandonkelly thanks! So that’s the config for the environment-label
plugin, and I was going to suggest this exact thing to them, as it doesn’t work otherwise.
Sorry, it was late and I missed that that was the Environment Label config. Updated my comment to reflect that.
(Sorry for delay, been out of the office sick) Yeah, this makes perfect sense. I suppose if it's important enough for us I can open up an issue on their repo about making this update. Though, either way, it does now occur to me that I want to make config values callable in any plugins I write moving forward. This would be a very reasonable default behavior for configs.
@engram-design I'm fine with closing out this issue unless you have some intention to do anything else with it.