Skip to content

Comments

[FIX] Has plugin fix#576

Closed
jaxwilko wants to merge 7 commits intowip/1.2from
wip/1.2-has-plugin-fix
Closed

[FIX] Has plugin fix#576
jaxwilko wants to merge 7 commits intowip/1.2from
wip/1.2-has-plugin-fix

Conversation

@jaxwilko
Copy link
Member

This PR resolves the issue raised in #575.

Simply it ensures that normalizeIdentifier() returns the value passed if the key is not found in the normalizedMap array.

@jaxwilko
Copy link
Member Author

Probably helps if I commit the new plugin that the tests are targeting

@jaxwilko
Copy link
Member Author

As a note, I've added some consts for plugin count in the PluginManagerTest class, this just makes it easier to maintain and reduces the amount of magic numbers in the test

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

@jaxwilko are you sure this fixes the issue, though? I don't see the link with replacementMap[]

@jaxwilko
Copy link
Member Author

jaxwilko commented Jun 15, 2022

@mjauvin the replacement map correctly stores normalized identifiers 'Winter.Original' => 'Winter.Replacement'

image

The normalized map also correctly stores lower keys to normalized identifiers 'lower.case' => 'Camel.Case'

image

The issue is when you normalize an identifier via normalizeIdentifier() it should strtolower() the input, check the normalizedMap and return any value found, returning the original input if no key was found. However the returned value was the string that had been ran through strtolower()

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

But this line will never return true for a replaced plugin:
https://github.com/wintercms/winter/blob/develop/modules/system/classes/PluginManager.php#L184-L189

@jaxwilko
Copy link
Member Author

Expanding on the above, when you call hasPlugin() it normalizes the identifier, then checks the replacement map, for the example of the test Winter.NotInstalled is not installed and therefore does not exist in the normalizedMap so returns the lower case version winter.notinstalled, which is not in either $this->plugins or $this->replacementMap. By adding the fix to return the passed value, Winter.NotInstalled is in $this->replacementMap and therefore hasPlugin() returns true

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

Oh, I get it now... but you still need to use the plugin name with the exact capitalization, otherwise it won't work... this is not true for the replacement plugin, though

@jaxwilko
Copy link
Member Author

But this line will never return true for a replaced plugin: https://github.com/wintercms/winter/blob/develop/modules/system/classes/PluginManager.php#L184-L189

The reason for this is we don't know the true normalized identifier for the plugin being replaced, so we just take whatever the replacement plugin suggests, if a developer accidentally provides:
image
Then they we will use that as the normalized identifier of the plugin being replaced as we have no way of checking for that plugins real code (as it may not be installed on the system).

It is down to the plugin developer to correctly implement the replacement, they should notice when testing that the plugin wont be flagged as replaced if they mistype.

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

>>> $pm->hasPlugin('Rainlab.Blog');
=> false

>>> $pm->hasPlugin('RainLab.Blog');
=> true

>>> $pm->hasPlugin('rainlab.blog');
=> false

vs

>>> $pm->hasPlugin('winter.blog');
=> true

>>> $pm->hasPlugin('Winter.blog');
=> true

>>> $pm->hasPlugin('Winter.Blog');
=> true

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

But this line will never return true for a replaced plugin: https://github.com/wintercms/winter/blob/develop/modules/system/classes/PluginManager.php#L184-L189

The reason for this is we don't know the true normalized identifier for the plugin being replaced, so we just take whatever the replacement plugin suggests, if a developer accidentally provides: image Then they we will use that as the normalized identifier of the plugin being replaced as we have no way of checking for that plugins real code (as it may not be installed on the system).

It is down to the plugin developer to correctly implement the replacement, they should notice when testing that the plugin wont be flagged as replaced if they mistype.

But why don't we put everything as lowercase internally, and always normalize the provided identifiers for any of the methods?

@jaxwilko
Copy link
Member Author

@mjauvin honestly that's what I'd prefer to do, we have to transform everything everywhere and it doesn't make much sense doing that. Would be really nice to just strtolower() everything and ignore casing.

Re: mixed casing hasPlugin we could look at something like this:

image

But I really don't like it

@mjauvin
Copy link
Member

mjauvin commented Jun 15, 2022

What's wrong with:

diff --git a/modules/system/classes/PluginManager.php b/modules/system/classes/PluginManager.php
index f2ba9cdbb..73a88c651 100644
--- a/modules/system/classes/PluginManager.php
+++ b/modules/system/classes/PluginManager.php
@@ -180,7 +180,7 @@ class PluginManager
         $replaces = $pluginObj->getReplaces();
         if ($replaces) {
             foreach ($replaces as $replace) {
-                $this->replacementMap[$replace] = $classId;
+                $this->replacementMap[$this->getNormalizedIdentifier($replace)] = $classId;
             }
         }  

@jaxwilko
Copy link
Member Author

I think that would work with the pervious version of normalizeIdentifier() which would return strtolower($code). However if we fix normalizeIdentifier() it wont solve the hasPlugin when calling with mixed cases.

We could revert back to the old version of normalizeIdentifier(), but I'm not a massive fan of that side effect.

@LukeTowers any thoughts?

@jaxwilko jaxwilko marked this pull request as draft June 15, 2022 18:57
@jaxwilko
Copy link
Member Author

I've marked this as a draft because while it resolves issues reported in #575 it adds in a lot of complexity with how we handle things internally.

This PR is more of a hack than a real fix at this time.

A proper solution would be to convert the internals of PluginManager to use lower cased identifiers, simplifying the logic for resolving plugins internally.

LukeTowers pushed a commit that referenced this pull request Jun 21, 2022
This modifies the plugin manager to internally treat plugin identifiers as lower case strings, only transforming them to their normalized versions when requested by methods like getPlugins() & getAllPlugins().

The idea behind this is that it provides a much simpler way to internally handle checking, especially for plugin replacement where casing could cause issues.

Replaces #576. Fixes #575.
@LukeTowers
Copy link
Member

Closing in favour of fba6446

@LukeTowers LukeTowers closed this Jun 21, 2022
@LukeTowers LukeTowers deleted the wip/1.2-has-plugin-fix branch June 21, 2022 21:55
LukeTowers pushed a commit that referenced this pull request Jun 22, 2022
This splits the testing suite into the separate modules as appropriate in order to improve the reliability of the testing suite as a whole and make it easier for developers to have an up to date testing suite from the core to build off of. Additionally the tests are now namespaced and some minor improvements to the PluginManager were made.

Now the PluginManager will internally treat plugin identifiers as lower case strings, only transforming them to their normalized versions when requested by methods like getPlugins() & getAllPlugins(). The idea behind this is that it provides a much simpler way to internally handle checking, especially for plugin replacement where casing could cause issues.

Replaces #576. Fixes #575.
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

Successfully merging this pull request may close these issues.

3 participants