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

Fix setter value type with prado tpl/Page #837

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

zendre4
Copy link
Contributor

@zendre4 zendre4 commented Dec 19, 2022

This is for fix #836 .

My fix ensure value for bool, integer, and float.

I test this on PHP 7.4 and 8.0. If union type are used, the fix do noting.

@belisoful
Copy link
Member

belisoful commented Dec 20, 2022

Why not the ensureString as well? As is a sanity check... setting a property with a <%= %> may not necessarily return a string.

@@ -441,6 +442,32 @@ protected function configureProperty($component, $name, $value)
}
}
$setter = 'set' . $name;
if (method_exists($component, $setter)) {
Copy link
Member

@belisoful belisoful Dec 20, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be updated to be behavior aware with #825

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this going to be $component->hasMethod($setter)

!empty($params[0]->getType()) &&
$params[0]->getType() instanceof \ReflectionNamedType
) {
switch ($params[0]->getType()->getName()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

between getting the "new reflectionclass()" and this type-name, caching the class/property/type into a static would greatly speed things up.

@@ -441,6 +442,32 @@ protected function configureProperty($component, $name, $value)
}
}
$setter = 'set' . $name;
if (method_exists($component, $setter)) {
if ($reflector = new \ReflectionClass($component)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The setter/property may not be in the component but in a behavior modifying the component. looping through each behavior would be needed too but that requires #826.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looping all the behaviors from here sounds time expensive (but can be fixed with some caching) but also a bit incorrect from an OOP point of view.
Maybe adding a way to get the reflected method from inside TComponent itself could be an idea. This would also move the reflection cache inside the class itself, so that other callers can benefit from it.

@belisoful
Copy link
Member

belisoful commented Dec 20, 2022

TPropertyValue::EnsureCode($github)

my apologies if my critiques sound harsh, they aren't. I like the idea of auto-ensuring typed setters. The full scope of PRADO is quite vast and each change, not matter how small, requires looking at the whole.

@zendre4
Copy link
Contributor Author

zendre4 commented Dec 20, 2022

Ok @belisoful I add the ensureString and I modify the code for stored the type in a variable, it's ok for you for this two part ?

Regarding issue #825 what do you expect from me, I can't use hasMethod because it doesn't exist yet. I can modify my if, but it will not merge until #825 is finished...

And for #826 I don't sure to understand the change

@belisoful
Copy link
Member

belisoful commented Dec 20, 2022

Adding the ensureString is great.

When I said to store the type in a variable I mean that a "static $cache" variable needs to be created. The cache needs to store the reflection based on the get_class($component). Then the static cache should store the setter method type for easy and quick retrieval from the cache. We want to only call Reflection on a class once, and we only want to get the setter type once. Retrieving the setter type from cache is much faster than calling the same thing over and over and over. For an example of what I am talking about, see TApplicationComponent::getClassFxEvents. That caches the data in a static as well as retrieves the data from the PRADO cache. Both of those are things we can do to speed up this code.

#825 and #826 is urgent and that is what I am focused upon. I am hoping to have this committed in the next day or two and merged shortly there after. You'll be able to use these methods from the main branch there after. My humble apologies for not having these completed long ago.

As for why #826 is important... It is possible for a behavior to implement a setter that doesn't exist in the owner's methods. So you'll need to loop through all the behaviors for the setters and their types beyond the main component.

Behaviors were added in 3.2.3 as a way of extending and changing the behavior of a TComponent. Also to be up-to-date technically with Yii (in that regard, a go beyond with "dy" and "fx" events). Behaviors can add events, properties, and methods to a TComponent that it doesn't originally have. A behavior can even make one object "look" and act like another.

A great example I love to use for behaviors is the "student" behavior for users. A StudentUserBehavior can add school class scheduling and grades properties to the TUser without having to have a separate structure with separate reference to maintain for each user. The TUser simply automatically gets the Student methods, events, and properties. If you want an example, see the Permissions manager TUserPermissionsBehavior for an example of how Advanced Behaviors are used. Also see the Prado\Util\Behaviors directory.

@zendre4
Copy link
Contributor Author

zendre4 commented Dec 20, 2022

ok I will wait for you to finish #825 and #826. After that, I'll use the new "hasMethod", and I'll try to use static and cache (I never used that in Prado yet)

@belisoful
Copy link
Member

belisoful commented Dec 20, 2022

Using PRADO cache may be overkill and can be implemented after the static variable is used to cache class-setter types.

What I am looking for is to only call the Reflection class once per class, and once per setter.

@belisoful
Copy link
Member

Also, when the getBehaviors method get implemented, take that array, prepend the original object, put the ensure code in a loop on each object in the array and you'll get the object and behavior setter type, in the proper order, easy-peasy.

@ctrlaltca ctrlaltca deleted the branch pradosoft:master December 30, 2022 11:17
@ctrlaltca ctrlaltca closed this Dec 30, 2022
@ctrlaltca ctrlaltca mentioned this pull request Dec 30, 2022
@ctrlaltca ctrlaltca reopened this Dec 30, 2022
@ctrlaltca ctrlaltca changed the base branch from main to master December 30, 2022 11:29
Copy link
Member

@ctrlaltca ctrlaltca left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks promising to me, as it solves the long time problem of interpreting the correct type for data coming from templates.
The ReflectionClass calls definitely needs some type of caching to avoid creating possibly hundreds of identical objects for a single template

@ctrlaltca
Copy link
Member

The ReflectionClass calls definitely needs some type of caching to avoid creating possibly hundreds of identical objects for a single template

From a few quick tests and some literature found on the web it seems that creating ReflectionClass objects is only expensive the very first time, while following object gets created in a negligible time.
Still, if this needs to be extended to methods introduced by behaviors, we need caching for our part.

@belisoful
Copy link
Member

belisoful commented Jun 13, 2023

scrubbing data types for function parameters is also needed for setting command line data in the shell. when --variable=someData_1234 the variable is mapped to a setter handler. The setter handler could read the function parameter data type and ensure to int, bool, float, string, array as well.

This functionality shouldn't be kept only in the template engine.

Also, This function is needed in the xml config.

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.

Problem with PHP type in setter value type with Prado tpl/Page.
3 participants