improve granular rendering #29

Open
dbu opened this Issue Oct 27, 2012 · 14 comments

Comments

Projects
None yet
3 participants
Collaborator

dbu commented Oct 27, 2012

follow-up of #27

we should have the hierarchy in the entities and make sure we only render namespaces and the collection about attribute if they are not rendered in the outside hierarchy.

this should even work when using the renderAttributes and renderContent and manually rendering properties and collections of entities.

dbu referenced this issue in symfony-cmf/symfony-cmf-website Oct 27, 2012

Open

[WIP] Handling of CreateJs on the CMF website #9

Contributor

adou600 commented Dec 18, 2012

The following GIST can help to identify the problems linked to the duplicate about attribute: https://gist.github.com/4328016

Problems identified:

  • Several "+Add" buttons are visible, 4 in this case
  • If a news is added, the news just created is displayed twice
  • Update the NewsCollection page will send a owl#Thing in the @type parameter of the HTTP PUT, in addition to CollectionPage. This doesn't appear in this example, but in symfony-cmf/symfony-cmf-website#9, this gives a HTTP response with the owl#Thing in addition as well in @type. Result: the first news in the list is duplicate and added at the end of the news list.
Owner

flack commented Dec 18, 2012

@adou600: I'm not sure I understand: The gist you linked was rendered by current CreatePHP? If so, could you also post the corresponding PHP or Twig template?

Because AFAICT the duplicate about rendering should be fixed since 4060055, so it would be interesting to see if there is a case we missed.

the problem with owl:Thing sounds like bergie/create#122, which also has been fixed recently, so maybe, your installation is just slightly behind the times

Contributor

adou600 commented Dec 19, 2012

@flack: yes, I use the latest createphp, the changes of 4060055 are present in my vendors. I added the twig template and the rdf-mapping in https://gist.github.com/4328016.

The special case here is that we have a CollectionPage (with title and description) containing the list of all NewsArticle.

The owl:Thing problem is indeed solved for usual cases. But it appears in addition to the real type (CollectionPage in our case), only when the description or title of CollectionPage is modified.

Owner

flack commented Dec 19, 2012

Looking at your code, I'm a bit unsure about https://gist.github.com/4328016#file-sandbox-mainbundle-document-newsarticle-xml-L9. IIUC, the rev has to be added to the parent type definition, not to the child one, but I might be wrong, @dbu knows this better than I do. But at least in my demo setup, I have rev at the parent entity and it works without problems

Owner

flack commented Dec 19, 2012

About owl:Thing: @bergie metioned to me once that typeof is a multivalue field, so it might be that it is by design that generic and specialized types are sent in one go. But then again, maybe it's just something that happens because Create.js misinterprets your HTML...

Owner

flack commented Dec 19, 2012

Looking at your twig, it's kind of unavoidable that the about attribute gets rendered twice: the detection code from 4060055 can only work if you render at least the property's start and end tag through CreatePHP API, but in twig, you only render the property's attributes and content. So createphp has no way of knowing if a collection is rendered inside of a parent container (since the opening/closing HTML tags are hardcoded in the template).

It would have to look something like this for the duplicate detection to work:

{% createphp cmfMainContent as="rdf" %}

{{ createphp_render_start(rdf) }}
    <h2 {{ createphp_attributes( rdf.title ) }}>{{ createphp_content( rdf.title ) }}</h2>
    <p {{ createphp_attributes( rdf.body ) }}>{{ createphp_content( rdf.body|raw ) }}</p>
    <ul {{ createphp_attributes( rdf.children ) }}>
        {% for news in cmf_children(cmfMainContent) %}
        {% createphp news %}
        <li {{ createphp_attributes(news_rdf) }}>
            <a href="{{ path(news) }}" {{ createphp_attributes(news_rdf.title) }}>{{ createphp_content(news_rdf.title) }}</a> ({{ news.publishStartDate | date('Y-m-d') }})
            <div class="newscontent" {{ createphp_attributes(news_rdf.body) }}>{{ createphp_content(news_rdf.body) }}</div>
        </li>
        {% endcreatephp %}
        {% endfor %}
    </ul>
{{ createphp_render_end(rdf) }}

{% endcreatephp %}

Of course, the functions createphp_render_start and createphp_render_end don't exist right now in CreatephpExtension, but I'll open a new ticket for that

Contributor

adou600 commented Dec 20, 2012

About https://gist.github.com/4328016#file-sandbox-mainbundle-document-newsarticle-xml-L9, the reverse mapping is needed in the child, at least if you want to create new content with PHPCR ODM. If I get it right, it was one of the goal of #34.

If you put the rev only in the parent, the RestService::_handleCreate will not be able to get the parent, by mapping the dcterm:partOf in the vocabulary to get the subject. If needed, maybe @dbu can confirm or precise that?

Contributor

adou600 commented Dec 20, 2012

I'm not sure to get the goal of createphp_render_start and createphp_render_end tags. What would they do exactly? Output the div containing the collection: https://gist.github.com/4328016#file-example-news-html-L74? Couldn't it be included into {% createphp cmfMainContent as="rdf" %}? Once we open createphp twig extension, we could be in a createphp context to be able to know we are in a parent container. Of course, it seems easier said than done... But may be this is also just a misunderstanding for my part.

Owner

flack commented Dec 20, 2012

The problem is that if you look at these two cases:

{% createphp cmfMainContent as="rdf" %}

<div class="newsoverview" {{ createphp_attributes(rdf) }}>
<h2 {{ createphp_attributes( rdf.title ) }}>{{ createphp_content( rdf.title ) }}</h2>

<ul {{ createphp_attributes( rdf.children ) }}>
    {% for news in cmf_children(cmfMainContent) %}
    {% createphp news %}
        <li {{ createphp_attributes(news_rdf) }}>
            <a href="{{ path(news) }}" {{ createphp_attributes(news_rdf.title) }}>{{ createphp_content(news_rdf.title) }}</a> ({{ news.publishStartDate | date('Y-m-d') }})
            <div class="newscontent" {{ createphp_attributes(news_rdf.body) }}>{{ createphp_content(news_rdf.body) }}</div>
        </li>
    {% endcreatephp %}
    {% endfor %}
</ul>

</div>

{% endcreatephp %}
{% createphp cmfMainContent as="rdf" %}

<div class="newsoverview" {{ createphp_attributes(rdf) }}>
    <h2 {{ createphp_attributes( rdf.title ) }}>{{ createphp_content( rdf.title ) }}</h2>
</div>

<ul {{ createphp_attributes( rdf.children ) }}>
    {% for news in cmf_children(cmfMainContent) %}
    {% createphp news %}
        <li {{ createphp_attributes(news_rdf) }}>
            <a href="{{ path(news) }}" {{ createphp_attributes(news_rdf.title) }}>{{ createphp_content(news_rdf.title) }}</a> ({{ news.publishStartDate | date('Y-m-d') }})
            <div class="newscontent" {{ createphp_attributes(news_rdf.body) }}>{{ createphp_content(news_rdf.body) }}</div>
        </li>
    {% endcreatephp %}
    {% endfor %}
</ul>

{% endcreatephp %}

In the first case, the ul should not have an about attribute, but in the second case, it needs it. But if you only call render_attributes, createphp has no way of knowing whether the property is rendered inside a parent node or not.

I'm not exactly sure what {% createphp cmfMainContent as="rdf" %} does, but if it doesn't output an HTML node with the correct attributes, it won't help. Create.js takes its information from the DOM tree, i.e. if the collection UL does not have a parent node with an about attribute, it needs the about attribute itself. render_start and render_end set the isRendering flag in the entity's representation, so that by the time we render a collection, we know if it's rendered inside of a parent node or not. The render_attributes call can't decide that, the only thing we could do is give it a second parameter where you can explicitly suppress the rendering of the about attribute.

In plain PHP, you could also do the following:

<div class="newsoverview" <?= $rdf->renderAttributes() ?>>
<h2 <?= $rdf->title->renderAttributes() ?>><?= $rdf->title->renderContent() ?></h2>
<?php
$rdf->children->unsetAttribute('about');
?>
<ul <?= $rdf->children->renderAttributes() ?>>
    <?php foreach ($rdf->children as $child)
    { ?>
        <li <?= $child->renderAttributes() ?>>
            <!-- output child data -->
        </li>
    <?php } ?>
</ul>

</div>

but I guess this goes against the twig design philosophy a bit, since you would (non-persistently) modify the entity during the output phase

Owner

flack commented Dec 20, 2012

Regarding your other comment: When I look at the code, I think your assumption is correct. but the strange thing is, in my demo setup, it only works if I set the rev on the parent type. But I think that's really a problem in my demo site somewhere...

Collaborator

dbu commented Jan 9, 2013

{% createphp cmfMainContent as="rdf" %} creates the createphp entity from a domain object to make it ready to be rendered. the reason we only render the attributes is that we think the template designer should be in control of the html tag and any class, id and so on attributes, not the metadata author. but maybe we can make the createphp twig tag trigger render the start method to output the outer tag. maybe adding an option to tell it not to output anything but still tell create that we start rendering here and will do the attributes thing ourselves. it leaves open a bit more room for breaking things, but if you need an explicit parameter to disable it, you should know what you are doing.

i think this needs nothing new on createphp class level (there is a method to just render the start tag without the whole properties and collections, right?) - but needs extending the twig extension. would that make sense? shall i sit together with @adou600 and see if i can explain him how this can be done?

Owner

flack commented Jan 9, 2013

@dbu: Yes, I agree that the attributes call gives the designer more flexibility, but like I mentioned in the example two comments above, the getAttributes call cannot detect if it is called inside a parent container (see the two examples for why it's impossible), so with get_attributes you will always have the duplicate about attribute, unless you remove it manually from the object before rendering the attributes.

@bergie mentioned once that the duplicate add button for two nested about attributes is actually considered a bug in VIE, so maybe the problem could be resolved this way, too

Collaborator

dbu commented Jan 9, 2013

what i wanted to suggest is that we change the twig extension to by default render the opening and the closing html tag and optionally disable that for the flexibility, but in that case still tell the entity being rendered that it should consider itself being currently under rendering. maybe just call the opening tag method but not output the result.

Contributor

adou600 commented Jan 10, 2013

@dbu @flack FYI and to illustrate the case discussed, the second problems explained in #29 (comment) (news added displayed twice) can be seen here: https://saucelabs.com/tests/b91e2610a5284dc0a6ae37b208d8c41c

CSS code has been written to hide the duplicated add buttons. This is the reason why you can see only one button in the video. But there are actually 4 add buttons.

About the last problem (modifying the NewsCollection page), the issue can be seen here: https://saucelabs.com/tests/91a24f3bed434629b1053ac4933f55ac.

I think these problems will be affected by the corrections discussed here. So I'm ready to try! :-)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment