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

ENH Convert scalars and arrays to viewable data #11227

Conversation

emteknetnz
Copy link
Member

Issue #11196

@emteknetnz emteknetnz changed the title ENH Convet scalars to viewable data ENH Convert scalars and arrays to viewable data May 10, 2024
@emteknetnz emteknetnz marked this pull request as draft May 10, 2024 00:04
@emteknetnz emteknetnz force-pushed the pulls/5/scaler-to-viewable branch 5 times, most recently from 2c39936 to f35e66c Compare May 13, 2024 00:13
@emteknetnz emteknetnz marked this pull request as ready for review May 13, 2024 01:44
Comment on lines +570 to +573
// Cast arrays to ArrayList by default
if (is_array($value) && $castingHelper === $this->config()->get('default_cast')) {
$value = ArrayList::create($value);
} else {
Copy link
Member

Choose a reason for hiding this comment

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

ArrayList converts associative arrays to ArrayData - should we do the same here?

Comment on lines +571 to +573
if (is_array($value) && $castingHelper === $this->config()->get('default_cast')) {
$value = ArrayList::create($value);
} else {
Copy link
Member

Choose a reason for hiding this comment

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

Why is this conditional on the casting helper being identical to the default cast?

$valueObject = Injector::inst()->create($castingHelper, $fieldName);
$valueObject->setValue($value, $this);
$value = $valueObject;
// Cast arrays to ArrayList by default
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
// Cast arrays to ArrayList by default
// Wrap arrays in ArrayList by default

Comment on lines -129 to +135
foreach ($this->items as $i => $item) {
foreach ($this->items as $item) {
if (is_array($item)) {
yield new ArrayData($item);
if (array_is_list($item)) {
yield new ArrayList($item);
} else {
yield new ArrayData($item);
}
Copy link
Member

Choose a reason for hiding this comment

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

I don't think we should be changing the way ArrayList works - people use ArrayList for purposes other than just use in templates, and this could break some logic people have that assumes the current logic will remain as-is.

Comment on lines +580 to 582
if (is_a($value, ArrayList::class)) {
$this->convertArrayListItemsToViewableData($value);
}
Copy link
Member

Choose a reason for hiding this comment

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

What about other list types? We have to assume someone has made other implementations of SS_List.

Copy link
Member

Choose a reason for hiding this comment

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

Making these changes in obj() is going to have wider ranging effects than just making things work in the templating system. These changes should all be done inside the template parser.

Copy link
Member Author

Choose a reason for hiding this comment

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

The way things are setup I really don't know how to do this.

My PageController has this

    public function ArrayTest()
    {
        return ['item3', 'item4'];
    }

My template has this

		<% loop $ArrayTest %>
			$Me
		<% end_loop %>

The generated template is this

$scope->locally()->obj('ArrayTest', null, true); $scope->pushScope(); while (($key = $scope->next()) !== false) {
$val .= '
			';

$val .= $scope->locally()->XML_val('Me', null, true);
$val .= '
		';


}; $scope->popScope(); 

$scope->locally()->obj('ArrayTest', null, true); will call SSViewer_DataPresenter::obj() which will call SSViewer_Scope::obj() which calls SSViewer_DataPresenter::getObj() which calls SSViewer_Scope::getObj() which call ViewableData::obj() which is where the code changes are. ViewableData::obj() is what actually gets stuff, in this case PageController::ArrayTest() AND it wraps the results in a cache.

When ViewableData::obj() encounters an array, before this PR, it would convert it to a DBText because that's the ViewableData.default_cast. So all I get to work with in SSViewer_Scope::getObj() is a DBText which is obviously no usable

While this recipe-sink CI has gone green with this PR, it seems fair enough being concerned about ViewableData::obj() having potential side-effects. Given that, we could target this to CMS 6 instead?

@GuySartorelli
Copy link
Member

GuySartorelli commented May 14, 2024

I had to dive in and try to get this working myself to wrap my head around it. I ended up with these commits which handle allowing primitives to be used in templates, and allowing iterators such as ArrayIterator to work natively in templates.

I cam to the same conclusion as you regarding arrays though - even though SSViewer_Scope::next() has a comment saying the item could be an array, and handles that, there's no way to actually have an array there unless we update ViewableData::obj() to return them.

What should we do?

I think we need to do two things:

  1. In CMS 5 allow primitives other than array. This is an improvement for simple use cases and doesn't require any BC breaking changes as my attempt shows. Looking at the commit history in this PR you had something very similar originally as well.
  2. In CMS 6 make whatever changes are necessary to get arrays working natively in templates. This could mean:
    1. Update ViewableData::obj() to return arrays directly if there are any
    2. Update ViewableData::obj() to wrap arrays in either a list or ArrayData depending on what type of array they are
    3. Update ArrayList to either never wrap arrays, or to always wrap them in either a list or ArrayData depending on what type of array they are
    4. Some combination of the above
    5. Decoupling the logic from ViewableData - though that may be more effort than it's worth
    6. Something else neither of us considered yet, if someone else has any ideas.

I'd say update this PR to handle point 1 above, and raise a new card to look at point 2 since that'll need to go through refinement.

Considering there's a ton of ways point 2 could go, that may even be worth discussing in an architecture catchup.

@emteknetnz
Copy link
Member Author

emteknetnz commented May 14, 2024

I'll close the PR to retain the diff for the CMS 6 card and open a new one to do just the scalars

@emteknetnz emteknetnz closed this May 14, 2024
@GuySartorelli GuySartorelli deleted the pulls/5/scaler-to-viewable branch May 16, 2024 01:11
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.

None yet

2 participants