-
Notifications
You must be signed in to change notification settings - Fork 27
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
Multiple dimension loops? #195
Comments
I would guess your outer loop would be |
I've been trying variations on that theme, but with no luck. For example, this: ol li {
repeat: data(output.benefit_data.eb);
}
tr {
repeat: iteration();
}
td span.benefit {
content: key();
}
td span.value {
content: iteration();
} Results in this fatal error: DOMDocument::createTextNode() expects parameter 1 to be string, object given
line 75 in file ../vendor/level-2/transphporm/src/Property/Content.php |
Can you isolate which TSS line is causing that error (I would guess it's one of the last two) by commenting one out at a time? |
It's the second |
Interesting. What is I would like to see what your output looks like if you change that line in $new->appendChild($document->createTextNode($node)); to this: $new->appendChild($document->createTextNode(get_class($node))); because apparently it's not a |
Give me a few minutes to edit |
So |
Yes, that's what it seems like. Results of get_class() expects parameter 1 to be object, string given
line 76 in file ../vendor/level-2/transphporm/src/Property/Content.php |
Oh, that makes sense. My fault. if ($node instanceof \DomText) $node = $node->nodeValue; add this: else if (is_object($node)) $node = get_class($node); I think that should do what I was intending. |
Ok, did that I think, if I managed to correctly follow your instructions. ;-) Output for the |
Ok, maybe that will be helpful in tracking down the issue. I'm not all that familiar with the code base but I do know that @TomBZombie likes to use plain objects sometimes, so I'm sure Transphporm is internally creating those somewhere for some reason. I'll dig around the code a bit until he gets here 😉 |
Actually, I just realized my real data contains a mix of arrays and objects, which I was just treating as an array of arrays, since Transphporm mostly does the same. Maybe that was a faulty assumption. That is, it appears the real data looks like this: array(
1 => stdClass(
'foo' => 'ThingOne AttributeOne',
'bar' => 'ThingOne AttributeTwo',
),
2 => stdClass(
'foo' => 'ThingTwo AttributeOne',
'bar' => 'ThingTwo AttirbuteTwo',
),
// Etc.
); |
I can see how you would assume that. What happens if you make it just arrays? |
I'm trying to figure out how to do that now. I'm displaying data that I receive from an API as JSON, so I'll need to write some PHP code to walk the data structure and convert objects to arrays, I think. |
Ultimately, I don't think you should have to do that, but at least for testing purposes it might be helpful. My best guess right now is that the issue lies in |
If I do the most simple minded thing of changing your else if (is_object($node)) {
// $node = get_class($node);
$node = (array)$node;
} Then I get this error: DOMDocument::createTextNode() expects parameter 1 to be string, array given
line 90 in file ../vendor/level-2/transphporm/src/Property/Content.php Line 90 in my hacked up code is the same place errors occurred earlier: $new->appendChild($document->createTextNode($node)); I guess really no surprise there. I will attempt to convert the objects to arrays in my data before calling Transphporm and see how that goes. |
I wonder... if (is_array($n)) { to this: if (is_array($n) || (is_object($n) && $n instanceof \stdClass)) { If that does what I think it does, you shouldn't see |
Making that change gets me the value parts of the |
Ah, it seems it is iterating through my entire li {
repeat: data(output.benefit_data.eb);
} |
I think this is where, having completed the discovery phase, I leave it in Tom's capable hands. 😉 |
Can you give me a complete example? One of the issues here is that transphporm sorts rules by specificity so the following rules: ol li {
repeat: data(output.benefit_data.eb);
}
tr {
repeat: iteration();
}
td span.benefit {
content: key();
}
td span.value {
content: iteration();
} Will get executed in this order:
With the following script: <?php
require 'vendor/autoload.php';
$data = array(
1 => [
'foo' => 'ThingOne AttributeOne',
'bar' => 'ThingOne AttributeTwo'
],
2 => [
'foo' => 'ThingTwo AttributeOne',
'bar' => 'ThingTwo AttirbuteTwo'
]
);
$tss = '
ol li {
repeat: data();
}
tr {
repeat: iteration();
}
td span.benefit {
content: key();
}
td span.value {
content: iteration();
}
';
$xml = '
<ol>
<li>
<table>
<tr>
<td><span class="benefit"></span></td>
<td><span class="value"></span></td>
</tr>
</table>
</li>
</ol>
';
$tpl = new Transphporm\Builder($xml, $tss);
echo $tpl->output($data)->body;
echo "\n"; This is the output: <ol>
<li>
<table>
<tr>
<td><span class="benefit">1</span></td>
<td><span class="value">ThingOne AttributeOneThingOne AttributeTwo</span></td>
</tr>
<tr>
<td><span class="benefit">1</span></td>
<td><span class="value">ThingOne AttributeOneThingOne AttributeTwo</span></td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<td><span class="benefit">2</span></td>
<td><span class="value">ThingTwo AttributeOneThingTwo AttirbuteTwo</span></td>
</tr>
<tr>
<td><span class="benefit">2</span></td>
<td><span class="value">ThingTwo AttributeOneThingTwo AttirbuteTwo</span></td>
</tr>
</table>
</li>
</ol> The li {
repeat: data();
}
tr {
repeat: iteration();
}
td span.benefit {
content: key();
}
td span.value {
content: iteration();
} Which now produces the correct output: <ol>
<li>
<table>
<tr>
<td><span class="benefit">foo</span></td>
<td><span class="value">ThingOne AttributeOne</span></td>
</tr>
<tr>
<td><span class="benefit">bar</span></td>
<td><span class="value">ThingOne AttributeTwo</span></td>
</tr>
</table>
</li>
<li>
<table>
<tr>
<td><span class="benefit">foo</span></td>
<td><span class="value">ThingTwo AttributeOne</span></td>
</tr>
<tr>
<td><span class="benefit">bar</span></td>
<td><span class="value">ThingTwo AttirbuteTwo</span></td>
</tr>
</table>
</li>
</ol> In 99% of cases we need to run outer blocks before inner blocks, consider this: main nav li {
repeat: data(nav);
}
main {
content: template('foo.xml');
} The second rule must be executed first. We can't really prioritise by content type (e..g content: template() or repeat()) because I might want to include a template for each iteration or iterate over an included template. It might be worth to add a |
Specifying rule execution order could help, but... I believe Chris approached this from the same logical standpoint that I did; namely, that selector specificity would not be the determining factor for loop nesting, but rather where each element falls in the DOM tree. In other words, it seems logical that if a selector of any specificity targets a given element with a I anticipate this being a point of confusion for consumers of this library until DOM level alone is made the determining factor for nesting. |
Because of Consider the following: main {
content: template('page.xml');
}
.sidebar li {
repeat: data(navigation);
} If the It would be possible to avoid this by working the other way around: Rather than looping through the rules and finding any element that matches the rules, we could iterate over every element in the document and then find any rules that apply to it. However, this would come at rather large expense to performance and make caching considerably less efficient as you'd still need to loop through every element. |
Looking at this: ol li {
repeat: data(output.benefit_data.eb);
}
tr {
repeat: iteration();
}
td span.benefit {
content: key();
}
td span.value {
content: iteration();
} It would be possible to look for things like |
Tom and Garrett: thanks for continuing the discussion. I'm really busy this weekend with non-programming projects, so I hope to get back to working on this on Monday. I'll post here when I have something of potential value. |
@TomBZombie I'd like to throw one more wrench into this issue, but I thought better of it so I'll be making it a separate thing. |
I tried rearranging my HTML to use the specificity order that Tom's example used, and that worked for my current data structure. Despite my knowledge of CSS, knowing the specificity order that Transphporm will use to evaluate rules is difficult. |
It will always execute by specificity so selectors with more parts will be executed first.
The reason for this is that, like CSS, you can have multiple rules that affect the same element. Consider: div span {content: "B"; }
span { content: "A"; } the |
I guess I missed the reality that my table rows were more specific than the list items, which enclosed the table. I was thinking that td span.benefit was really only more specific than tr { ... } completely missing that even the naked ol li { ... } rule. I guess all we need is a bit of documentation in the Wiki on this, and the ticket can be closed. |
What do you mean? How could |
Because the Or it could be that I'm completely confused in trying to understand how and why Transphporm processes the rules in the order that it does. :-p I think it's probably the latter. I am confused. |
Following CSS specificity rules, |
Thanks. It makes perfect sense when I'm working with CSS, but for some reason I get muddled when working with |
Maybe I should write the Wiki documentation for this. If I get it right there, (checked by you and Tom?), then I'll never have to worry again. :-) |
I'm going to improve the way it works and allow arbitrary ordering and not using specificity for everything. I think this should work:
|
I'm not sure you need to make any changes. With some documentation, specificity works fine. Which consumes fewer resources? |
How it is now will be faster, but with caching enabled won't make much difference. |
That new logic seems sound. I like it. |
Is there anyway in TSS to loop through more than one dimension of a data structure? For example, if my data contained:
I'd like a way to loop through and display all the strings above. Is this possible? If not, I can work out a way to flatten my data structure before passing it to Transphporm.
The text was updated successfully, but these errors were encountered: