8000 Fix empty text transformer to not treat zero as empty text by rokaszygmantas · Pull Request #9120 · PrestaShop/PrestaShop · GitHub
[go: up one dir, main page]

Skip to content

Fix empty text transformer to not treat zero as empty text #9120

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

Merged

Conversation

rokaszygmantas
Copy link
Contributor
@rokaszygmantas rokaszygmantas commented May 24, 2018
Questions Answers
Branch? develop
Description? You cannot save "0" as a value in TextType form fields. It's transformed into an empty string, because 0 is considered an empty value. This PR makes text fields to allow saving 0.
Type? bug fix
Category? CO
BC breaks? no
Deprecations? no
Fixed ticket? n/a
How to test? Go to BO and edit a product. In "Prices" tab, set unit field to 0, hit save. Reload the page. It should show 0 in the unit field. (unit field: https://prnt.sc/jm2ya9). Before it would show empty value after entering 0 and saving. This applies to all the text fields in migrated pages, that allow entering 0 as a value.

This change is Reviewable

@prestonBot prestonBot added the develop Branch label May 24, 2018
@mickaelandrieu mickaelandrieu added the Bug Type: Bug label May 25, 2018
@mickaelandrieu mickaelandrieu added this to the 1.7.5.0 milestone May 25, 2018
@PierreRambaud
Copy link
Contributor

Look at the class name TextEmptyType, it's maybe the desired behavior :/
@mickaelandrieu @Quetzacoalt91 wdyt?

@mickaelandrieu
Copy link
Contributor

it is TextEmptyType class, I don't understand lol

@rokaszygmantas
Copy link
Contributor Author

The problem is that there are some text types that must allow zero as a value. One good example is in shipping->preferences page the "free shipping starts at" field. It must allow saving 0 but it doesn't because 0 is transformed i to an empty string and empty string is not a valid value.
Tomorrow I'll provide a more detailed explanation to try to convince you that this is a bug :D don't have a computer near me today

@mickaelandrieu
Copy link
Contributor

@rokaszygmantas I'm already convinced because I'm aware that empty(0) returns true :)

@rokaszygmantas
Copy link
Contributor Author

True that. But do you see the described situation as a bug or do you think it's intended behaviour? :)

@PierreRambaud
Copy link
Contributor

What really happened if the value is empty (0, or ''), is that break something with your template, controller or something? If it's break something, maybe we need to change the field type by a NumberType ?

@rokaszygmantas
Copy link
Contributor Author

Yes, in my case the field is in shipping > preferences page, called "free shipping starts at" and it allows to enter weight. Number type would fit here but it needs to show weight unit next to the field, so I used TextWithUnitType for it.

@rokaszygmantas
Copy link
Contributor Author

I think the problem can be better seen with these fields:

  • product reference, supplier reference, product attribute reference,
  • product features custom value (https://prnt.sc/jnhbdq)
    to me it looks essential to allow entering zero in feature value or in product reference fields, but now you cannot save it with entered 0. What do you think @PierreRambaud @mickaelandrieu ?

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

How about:

// empty(0) returns true...
return (empty($data) && is_null($data)) ? '' : $data;

We keep the "right" condition and fix the bug that comes from PHP 💪

@PierreRambaud
Copy link
Contributor
PierreRambaud commented May 28, 2018

@mickaelandrieu Your test is wrong, no need to do an empty if you use is_null :/

$ php test.php                                                                                           
Value                                                                                                    
int(0)                                                                                                   
Result                                                                                                   
int(0)                                                                                                   
                                                                                                         
                                                                                                         
Value                                                                                                    
string(1) "0"                                                                                            
Result                                                                                                   
string(1) "0"                                                                                            
                                                                                                         
                                                                                                         
Value                                                                                                    
string(0) ""                                                                                             
Result                                                                                                   
string(0) ""                                                                                             
                                                                                                         
                                                                                                         
Value                                                                                                    
array(0) {                                                                                               
}                                                                                                        
Result                                                                                                   
array(0) {                                                                                               
}                                                                                                        
                                                                                                         
                                                                                                         
Value                                                                                                    
NULL                                                                                                     
Result                                                                                                   
string(0) ""                                                                                             
                                                                                                         
                                                                                                         
Value                                                                                                    
double(0)                                                                                                
Result                                                                                                   
double(0)                                                                                                
                                                                                                         
                                                                                                         
Value                                                                                                    
bool(false)                                                                                              
Result                                                                                                   
bool(false)

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

@PierreRambaud please add your test before saying mine is wrong :)

dont_think_so_bro

Note that I keep 'empty()' for explicit the "intent" of the test, of course we could remove it 👍

@PierreRambaud
Copy link
Contributor
foreach ([0, '0', '', array(), null, 0.0, false] as $var) {
    echo "Value" . PHP_EOL;
    var_dump($var);
    echo "Result" . PHP_EOL;
    var_dump((empty($var) && is_null($var)) ? '' : $var);
    echo PHP_EOL. PHP_EOL;
}

So if we can remove, the original PR is good, we can just do null === $data

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

So if we can remove, the original PR is good, we can just do null === $data

We can but I don't think we "should". We are fixing a bug from PHP here, but our intent is to allow input type with "empty" text, not "nullable" one. Being empty and being null is not the same!

@PierreRambaud
Copy link
Contributor

I don't understand where the PHP bug is, it's normal behavior for empty function. If we check for empty AND is_null, we just need to check for is_null because null is empty. It's exactly like making this test: $var === false AND empty($var).

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

We disagree on this: empty(0) and empty('O') shouldn't return true ^^.

If we change the test from "empty" to "null" we must the class name so we must create another FormType named TextNullableType or something like that.

@PierreRambaud
Copy link
Contributor
PierreRambaud commented May 28, 2018

But it's clearly weird and useless to have an empty and is_null function in the same line :/
If it's about the class name, maybe we must change the input type for some field, using NumberType for example with an allow_empty.
Plus, watch out with is_null, using === null is at least 8 times faster (from lot of benchmark)

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

Plus, watch out with is_null, use === null is at least 8 times faster (from lot of benchmark)

I'm not against using ===, I'm against using a class name not related to what we are doing in it: it's not SOLID and we should stop doing that cause of bugs of PHP language :)

and useless

it's not! It describes the intent of the class: it's also useless to have real variables names like $users, we could name our variables $a, $b, $c and $d. For the PHP engine, it's even better but we write code for developers and not for the engine.

maybe we must change the input type for some field, using NumberType for example with an allow_empty

Thinking about it, it's not always possible as some fields should accept strings or floats values. In all cases, the form component retrieves string values from client data and then do the casts when needed. In the specific use case of custom values, we can't use NumberType form.

Also, how about TextareaEmptyType form? Probably the same bug, even if it's really uncommon to set "0" as value in a textarea input (used for descriptions fields most of the time)

To sumup my pov on this patch:

  • opposed to use only null check on class used to check empty values
  • not opposed to define a new class called TextNullableType and use it instead
  • focused on keeping the code SOLID, no matter the quality of tools we use (PHP included)
  • Agree on using strict check instead of is_null function 👍
  • Don't forget that we also have the same input for textareas (so called TextareaEmptyType)

@PierreRambaud
Copy link
Contributor

it's not SOLID and we should stop doing that cause of bugs of PHP language :)

So it's a class name problem not a PHP bug. (Because it's not a bug just a stupid feature :trollface: ).

Otherwise, we have a class which name is TextEmptyType, who finally only check for null value.

Adding a empty check doesn't make the class SOLID too, having or not empty, the result will be the same, so you add a function which at the end, test something for nothing.

More, and because the is_null test is useful, we can maybe just use the default TextType and use options to allow_empty or not?

@mickaelandrieu
Copy link
Contributor
mickaelandrieu commented May 28, 2018

We can't rely on default TextType for a totally different reason => #5822 (yes, I'm the author of these classes ^^).

This weird behavior of Symfony may have been fixed in v3 (empty values are not "posted"), I don't know :)

EDIT: bip bip! It has been fixed since Symfony 3.1 => symfony/symfony#5906 let's use original {Text|TextArea}Type instead, and deprecate my owns 🎉

@rokaszygmantas what you need to do:

We can't remove these classes right now, to keep the compatibility.

@rokaszygmantas
Copy link
Contributor Author

after removing the empty text types service declarations, use case from this pr is no longer working: #5822 - I cannot save empty value for stock label 😕. I'll debug it a bit more tomorrow 🙂

@mickaelandrieu
Copy link
Contributor
mick 67E6 aelandrieu commented Jun 8, 2018

@rokaszygmantas shouldn't use the default label as default value?

Maybe it's a side effect of a patch of Symfony => https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Form/Extension/Core/Type/TextType.php#L28

@mickaelandrieu
Copy link
Contributor

@rokaszygmantas let me know when you have time for this, I'd like to see this pull request merged by the end of the week 👍

@rokaszygmantas
Copy link
Contributor Author

@mickaelandrieu sorry for delaying this PR. I'll try to tackle it ASAP.

I've investigated the issue with stock label a bit more and found out there are two problems actually:

  1. Problem 1: when you leave the "Label when out of stock" (code name available_later) field completely empty, it does not save.
    Facts:

  2. Problem 2: when you enter "0" in the same field, it persists as an empty string.
    Facts:

    • Since I've tested this after deprecating the TextEmptyType, the "0" value remains the same in $_POST after symfony handles the form (which is good).
    • In a similar fashion to Problem 1, the $_POST values are being filled into Product object in the legacy controller's code.
    • The legacy controller calls ObjectModel::update() on the Product.
    • In the ObjectModel::update() we have the same issue with if (!empty("0")) so it becomes an empty string: https://github.com/PrestaShop/PrestaShop/blob/develop/classes/ObjectModel.php#L380 🤔

It looks like those two bugs now are coming from legacy code, wdyt @mickaelandrieu? 🪲 🪲

@mickaelandrieu
Copy link
Contributor

@rokaszygmantas thanks for the information, really interesting and looks like an issue not related to the migration of your page at all.

What I think now: we need to address these 2 bugs but I want you to stay focused on migration, so we will find someone else to work on this /c @eternoendless

Regarding the page you have migrated, I think will should merge it with this known issue in mind.

@mickaelandrieu mickaelandrieu self-assigned this Jun 26, 2018
@mickaelandrieu mickaelandrieu force-pushed the fix_empty_text_type branch 2 times, most recently from 3cf6988 to 72074ec Compare June 26, 2018 15:41
@@ -59,7 +59,8 @@ public function __construct(
array $locales,
CurrencyDataProvider $currencyDataProvider,
array $tosCmsChoices
) {
)
Copy link
Contributor

Choose a reason for hiding this comment

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

it's weird, not in psr2 or symfony rules :/

Copy link
Contributor

Choose a reason for hiding this comment

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

Which rule do you use to have this?

$form->add('file', 'Symfony\Component\Form\Extension\Core\Type\FileType', array('mapped' => false));
$form->add('name', 'Symfony\Component\Form\Extension\Core\Type\TextType', array('mapped' => false));
$form->add('file', FileType::class, ['mapped' => false]);
$form->add('name', FileType::class, ['mapped' => false]);
Copy link
Contributor

Choose a reason for hiding this comment

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

Name must be a text type

[],
'Admin.Catalog.Feature'
) . ' (';
'Use default behavior',
Copy link
Contributor

Choose a reason for hiding this comment

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

weird indent, which rule do you used?

Copy link
Contributor

Choose a reason for hiding this comment

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

fixed manually

Copy link
Contributor
@PierreRambaud PierreRambaud left a comment

Choose a reason for hiding this comment

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

One bug, I will have a new review on tomorrow, in case I missed something.

@PierreRambaud
Copy link
Contributor

@mickaelandrieu What rules do you used for cs fixer, some aren't in PSR2, PSR1, and not even in Symfony rules?

@mickaelandrieu
Copy link
Contributor

@PierreRambaud I'll check my PHPStorm rules, but nothing I have personally set up

@mickaelandrieu
Copy link
Contributor

@PierreRambaud I've fixed the wrong form type and used PHP CS Fixer on the folder: I'm not sure this change the weird indentation you noticed :/

@PierreRambaud
Copy link
Contributor

What do you mean by PHP CS Fixer on the folder didn't find any cs fixer folder in source -_-'
We really need to define what rules we will used as soon as possible, we can't continue to code as we want :/

@@ -33,17 +34,17 @@ class TinyMceMaxLengthValidator extends ConstraintValidator
{
public function validate($value, Constraint $constraint)
{
$replaceArray = array(
$replaceArray = [
"\n",
"\r",
"\n\r",
Copy link
Contributor
@PierreRambaud PierreRambaud Jun 27, 2018

Choose a reason for hiding this comment

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

I just like how this line is useless when the first and second one can do the job --'
More I found a potential problem in the future here:

$str     = "Line 1\nLine 2\rLine 3\r\nLine 4\n";
$order   = array("\n", "\r");
$replace = '<br />';

$newstr = str_replace($order, $replace, $str);
var_dump($newstr);

// Will produce
/*
$ php test.php 
/home/got/test.php:10:
string(54) "Line 1<br />Line 2<br />Line 3<br /><br />Line 4<br />"
*/

When

$newstr = str_replace($order, [$replace], $str);

// Will produce
/*
$ php test.php 
/home/got/test.php:10:
string(42) "Line 1<br />Line 2Line 3<br />Line 4<br />"*/

As you can see, it is replaced by null and not an empty string (because index isn't found).

Currently null = '' but this isn't what we expect.

Copy link
Contributor

Choose a reason for hiding this comment

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

we agree I shouldn't change this behavior in this pull request, am I right?

Copy link
Contributor

Choose a reason for hiding this comment

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

I think you can, otherwise we'll never fixed it! (or not now at least)
Leave your code better than you found it. (https://deviq.com/boy-scout-rule/ in Agile XP)

Copy link
Contributor
@mickaelandrieu mickaelandrieu Jun 29, 2018

Choose a reason for hiding this comment

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

Don't you think it's already far better? My fix concerns only 10 lines of this pull request, I've improved SIXTY-EIGHT files.

More, I don't want to change the behavior and risk a regression on it.

@mickaelandrieu
Copy link
Contributor

Ping @prasanthSelvar It fixes the issue you pointed in #9094, would you mind to validate it?

@mickaelandrieu mickaelandrieu added the Waiting for QA Status: action required, waiting for test feedback label Jun 29, 2018
@prasanthSelvar prasanthSelvar added QA ✔️ Status: check done, code approved and removed Waiting for QA Status: action required, waiting for test feedback labels Jun 29, 2018
@mickaelandrieu
Copy link
Contributor

wdyt @PierreRambaud?

@PierreRambaud PierreRambaud merged commit 6e41834 into PrestaShop:develop Jul 2, 2018
@PierreRambaud
Copy link
Contributor

Thanks @mickaelandrieu

@rokaszygmantas rokaszygmantas deleted the fix_empty_text_type branch July 16, 2018 14:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Bug Type: Bug develop Branch QA ✔️ Status: check done, code approved
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants
0