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

Value of associative array not shown/rendered when key contains dot #391

Open
di-hardt opened this issue Jul 4, 2018 · 4 comments
Open

Comments

@di-hardt
Copy link

di-hardt commented Jul 4, 2018

Hello everyone,

got an interesting problem with accessing an associative array when the key contains a dot. Consider the following example:

$hp_institutes = array(
    "St. Mungos Hospital" => "Hospital",
    "Hogwarts" => "School"
);

in my view I use something like this:

<ul class="list-group">
  <f:for each="{hp_institutes}" as="hp_institute" key="hp_institute_key">
    <li class="list-group-item">
      {hp_institute_key} - {hp_institutes.{hp_institute_key}}
    </li>
  </f:for>
</ul>

which results in:

<ul class="list-group"><li class="list-group-item">
    St. Mungos Hospital - 
  </li>
  <li class="list-group-item">
    Hogwarts - School
  </li>
</ul>

The exact observer recognizes that the value of St. Mungos Hospital after the hyphen is missing. When I remove the dot and reload, the value is present.

Can anyone replicate this bug?

Best Regards,
Dirk

@NamelessCoder
Copy link
Contributor

Though I haven't tested it, I can explain why this happens:

Recursive object accessors are resolved by string value until all nested accessors are converted to strings. In the use cae above, the final object accessor node value becomes hp_institutes.St. Mungos Hospital which means the dot is considered as a sub-path. The variable that would be returned, would be $hp_institutes['St'][' Mungos Hospital'].

The entire strategy would have to be changed to support this. And the main problem with that is this would require a completely new node type, or a breaking change to the current object accessor node type.

Main challenge: nested object accessor syntax does not get expanded to nodes which are then evaluated, and converting it to such is complicated not in terms of doing it, but in terms of doing it as a non-breaking change.

You should work around this by creating smaller associative arrays as values of the main array, so you can access it with <f:for each="{institutes}" as="institute">{institute.name} - {institute.type}</f:for>. And in the very specific use case you posted above, the right solution is:

<ul class="list-group">
  <f:for each="{hp_institutes}" as="hp_institute" key="hp_institute_key">
    <li class="list-group-item">
      {hp_institute_key} - {hp_institute}
    </li>
  </f:for>
</ul>

Because you're assigning both the value and the key, you simply do not need to use a recursive object accessor to reference the value. It's more efficient this way. I'm aware this example is just for demonstration purposes - but my point is that the specific use case you wrote is very rare (your issue is the first appearance since this was added years ago). The standard use case of getting the key as a dynamic value is a lot less likely to be using dots in names. That doesn't mean it isn't a problem - just that its not a very frequent one and so solving it is likely to get very low priority.

@di-hardt
Copy link
Author

di-hardt commented Jul 9, 2018

Thank you for the confirmation, I thought so.

Yes, fix this will consume much time but I think, for the completeness of Fluid, it is necessary. PHP does not restrict me in the way of choosing the key length or the used charachters of a key, why should Fluid?

Your are right, this is only a simple example to show the issue but I think it is not a rare usecase. I am often in a situation, to sort data for categories or something. A key-value-hash (like in my example) is exectly what I need to access the sorted data easily and qickly without knowing on which index or in which variable they stored. Particular for accessing external API's with bad constructed datasets and associations this approach is very useful.

Before I wrote this issue I convert my datastructure to work around this issue. But now I have some more unnecessary computational steps which cost some time (not much of course but in some situations noticeable).

@stoppeye
Copy link

stoppeye commented Aug 6, 2020

I ran into the same problem today. In my case I have two arrays, one with questions from a questionnaire and one with answers, indexed by question identifiers. When looping over the the questions array I want to retrieve the answer value by accessing the answers array via the question identifier (eg. {answers.{id}} ). But the questions identifiers happen to have the format S_L_1.1, S_L_1.2, S_L_1.3 etc. So in my case, the "solution/workaround" as shown above is not applicable. I guess I'll have rewrite the identifiers in some way before assigning the arrays to the view.

I agree with @dirkwink that this should be a valid use case. Sometimes you don't have control over the keys of an array and - generally speaking - a dot is not a terribly exotic character in an array key.

I wonder, if there could be some kind of escaping mechanism that would allow me to write something like {answers.S_L_1.1}.
Of course, as soon as we're dealing with eg. a loop variable, we need another solution. But if an escaping mechanism existed, one could at least imagine something with (a yet to be written) VH like {answers.{id->format.quotemeta()}}. I don't know how terrible this would be in terms of performance though...

You speak of this being a very rare use case. But I wonder how often it is desirable to have a scenario like {var1.{var2}} where you would actually want this to be expanded into {var1.key.sub}, assuming that {var2} contains the value "key.sub"?
Based on my escaping approach, I could modify your quote above into "until all nested accessors are converted to escaped strings". If that was the default behaviour, one could think of something like {var1.{var2->format.raw()}} (or should that be {var1.{var2}->format.raw()}?) for cases, where you actually wanted the current behaviour. But obviously that would be a breaking change and I'm not aware of all the implications that would have...

@aimeos
Copy link

aimeos commented Jun 3, 2021

In Aimeos, all item keys contain dots and the missing support for escaping them by e.g. {data.product\.id} makes it very hard to use Fluid for Aimeos templates.

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

No branches or pull requests

4 participants