Jump to content

$fields->filter('type=FieldtypePage') doesn't work - why?


Gadgetto
 Share

Recommended Posts

I have a function which returns a WireArray of field names based on allowed field types. When I set $allowedFieldTypes to 'FieldtypePage' it doesn't return anything - although the template definitely has a field with this type. Setting $allowedFieldTypes to 'FieldtypeText' (or other existing field types) it works as expected.

This is the method:

    /**
     * Get all fields from product template
     * 
     * @param string $defaultFieldName
     * @param array $allowedFieldTypes
     * @return WireArray $fields
     * 
     */
    private function _getProductTemplateFields($defaultFieldName, array $allowedFieldTypes = array()) {
        $fields = new WireArray();
        if ($productTemplate = $this->wire('templates')->get(MarkupSnipWire::snipcartProductTemplate)) {
            $fields = $productTemplate->fields;
            if ($allowedFieldTypes) $fields->filter('type=' . implode('|', $allowedFieldTypes));
        } else {
            $defaultField = $this->wire('fields')->get($defaultFieldName);
            $fields->add($defaultField);
        }
        return $fields;
    }

This call works:

            $allowedFieldTypes = array(
                'FieldtypeText',
                'FieldtypeTextLanguage',
                'FieldtypePageTitle',
                'FieldtypePageTitleLanguage',
            );
            $productTemplateFields = $this->_getProductTemplateFields($defaults['data_item_name_field'], $allowedFieldTypes);
            foreach ($productTemplateFields as $ptField) {
                $f->addOption($ptField->name, $ptField->name, array());
            }

This not:

            $allowedFieldTypes = array(
                'FieldtypePage',
            );
            $productTemplateFields = $this->_getProductTemplateFields($defaults['data_item_categories_field'], $allowedFieldTypes);
            foreach ($productTemplateFields as $ptField) {
                $f->addOption($ptField->name, $ptField->name, array());
            }

Edit: If I remove the filter temporarily it returns all template fields including the field with type 'FieldtypePage'!

Am I overlooking something?

-- Martin

Link to comment
Share on other sites

Not an answer to your question. Is this a typo here or your actual code?

// assignment operator and not comparison operator
if ($productTemplate = $this->wire('templates')->get(MarkupSnipWire::snipcartProductTemplate)) {}

In addition, isn't this meant to be a non-empty array check? Did PHP 7 change this type of check?

if ($allowedFieldTypes)

 

Edit

Tested and filtering  works fine for me with 'FieldtypePage'

Link to comment
Share on other sites

14 minutes ago, kongondo said:

Not an answer to your question. Is this a typo here or your actual code?


// assignment operator and not comparison operator
if ($productTemplate = $this->wire('templates')->get(MarkupSnipWire::snipcartProductTemplate)) {}

In addition, isn't this meant to be a non-empty array check? Did PHP 7 change this type of check?


if ($allowedFieldTypes)

 

The first one is the actual code. The assignment within a comparison is a legitimate usage.

And yes, the second one is an empty array check. Is this not allowed in PHP 7? It works and throws no warning or error.

Link to comment
Share on other sites

1 minute ago, Gadgetto said:

The first one is the actual code. The assignment within a comparison is a legitimate usage.

Ah I see. I mistakenly thought you wanted to do a comparison.

2 minutes ago, Gadgetto said:

And yes, the second one is an empty array check. Is this not allowed in PHP 7? It works and throws no warning or error.

Yes, it does work. I was just wondering if it is a new PHP 7 feature or a PHP quirk. I am just used to count(array) or empty(array)

Btw, did you see my edit above? The filter works fine for me with FieldtypePage check.

  • Like 1
Link to comment
Share on other sites

8 minutes ago, kongondo said:

Yes, it does work. I was just wondering if it is a new PHP 7 feature or a PHP quirk. I am just used to count(array) or empty(array)

An empty array is "false" in PHP so I'm using this as it is the fastest possible comparison. ?

count($array) will be a lot slower (especially on larger arrays).

12 minutes ago, kongondo said:

Btw, did you see my edit above? The filter works fine for me with FieldtypePage check.

This is strange, I really don't know why it doesn't get a match for the Page field.

This is the field config:

910944127_Bildschirmfoto2019-12-14um13_28_06.png.f6822f5167d9079bb91192401cc9d83b.png

and this the template:

2081649122_Bildschirmfoto2019-12-14um13_28_38.png.c3e56088b72a9e48a4901d2e21d8b13d.png

 

Link to comment
Share on other sites

This gets crazy now:

I have 2 calls for the exact same method. With the first call the Page field is returned but not with the second one. WTF?

Is there some caching involved or could it be an issue with an array pointer?

Link to comment
Share on other sites

OK, I solved it this way (without using the filter method of WireArray):

    private function _getProductTemplateFields($defaultFieldName, array $allowedFieldTypes = array()) {
        $selectedFields = new WireArray();
        if ($productTemplate = $this->wire('templates')->get(MarkupSnipWire::snipcartProductTemplate)) {
            $templateFields = $productTemplate->fields;
            foreach ($templateFields as $field) {
                if (in_array($field->type, $allowedFieldTypes)) {
                    $selectedFields->add($field);
                }
            }
        } else {
            $defaultField = $this->wire('fields')->get($defaultFieldName);
            if ($defaultField->name) $selectedFields->add($defaultField);
        }
        return $selectedFields;
    }

 

Link to comment
Share on other sites

5 hours ago, Gadgetto said:

I have 2 calls for the exact same method. With the first call the Page field is returned but not with the second one. WTF?

It would happen to any fieldtype since filter() and not() methods are destructive. On the first call the $fields array ($productTemplate->fields) would contain all fields, after applying filter it would contain only filtered fields. On the second call of your function $productTemplate->fields does not returns all fields but only filtered fields ('FieldtypeText', 'FieldtypeTextLanguage', 'FieldtypePageTitle' and 'FieldtypePageTitleLanguage') and FieldtypePage is not among them. Use find() instead of filter() as it returns a new WireArray, this might work:

 
            if ($allowedFieldTypes) $fields = $fields->find('type=' . implode('|', $allowedFieldTypes));
 

 

  • Like 5
Link to comment
Share on other sites

21 hours ago, Gadgetto said:

An empty array is "false" in PHP so I'm using this as it is the fastest possible comparison. ?

count($array) will be a lot slower (especially on larger arrays).

A bit off-topic, but while typecasting an empty array to boolean does indeed result in false, "empty($array)" has its benefits. It's slightly more verbose, but it also won't cause a notice if $array hasn't been defined yet, and it's arguably more obvious (leading to better readability). Relying on typecasting can sometimes result in obscure issues, as well as make the code ever so slightly harder to decipher.

Using "count" to check if an array is empty is a common mistake. Even if in most cases the actual performance difference is too small to really matter, there's no reason to do this ??

  • Like 6
Link to comment
Share on other sites

21 hours ago, matjazp said:

It would happen to any fieldtype since filter() and not() methods are destructive. On the first call the $fields array ($productTemplate->fields) would contain all fields, after applying filter it would contain only filtered fields. On the second call of your function $productTemplate->fields does not returns all fields but only filtered fields ('FieldtypeText', 'FieldtypeTextLanguage', 'FieldtypePageTitle' and 'FieldtypePageTitleLanguage') and FieldtypePage is not among them. Use find() instead of filter() as it returns a new WireArray, this might work:


 
            if ($allowedFieldTypes) $fields = $fields->find('type=' . implode('|', $allowedFieldTypes));
 

 

Thanks! This works perfectly!

But I don't understand how the destructive behavior works. Is this cached somewhere? Or via static objects?

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...