Closed neznaika0 closed 2 weeks ago
Added repo https://github.com/neznaika0/appstarter/tree/fragents-data
Run ./spark serve
and uncomment different examples
Thank you - I'll look into it after the weekend.
I'm close to a solution. The first error is that renderFragment()
always returns the first fragment. There may be several of them, it is always an array.
[fragments:protected] => Array
(
[include] => Array
(
[0] => <div style="background-color: lightpink;width:500px;height: 20px;">
<b>Include Frag</b>
<b>foo: </b> YES <b>bar: </b> YES <b>baz: </b> NO <b>too: </b> YES <b>inc: </b> NO</div>
[1] => <div style="background-color: lightpink;width:500px;height: 20px;">
<b>Include Frag</b>
<b>foo: </b> YES <b>bar: </b> YES <b>baz: </b> NO <b>too: </b> YES <b>inc: </b> YES</div>
)
)
[fragmentStack:protected] => Array
(
)
Other questions.
<?= $this->extend('/htmx/layout') ?>
<?php $this->section('content') ?> <?php $this->fragment('fragment1') ?> ... <?php $this->endFragment() ?> <?= $this->include('/htmx/include') ?> <?php $this->endSection() ?>
2. How should the fragment/include be displayed if the section is specified, but it is outside?
```php
<?= $this->extend('/htmx/layout') ?>
<?php $this->section('content') ?>
...
<?php $this->endSection() ?>
<?php $this->fragment('fragment1') ?>
...
<?= $this->include('/htmx/include') ?>
<?php $this->endFragment() ?>
<?= $this->include('/htmx/include') ?>
It is logical not to use fragments outside the section. And include()
should be read 100%, but obey the rules of fragments and sections.
There are no restrictions without specifying a section - we show everything
Draft PR #77
Generally, view_fragment
should work the same as view
but only return the given fragment.
Thank you for starting work on this.
I don't understand how templates work well. Their nesting should essentially be like in PHP. https://www.php.net/manual/en/language.variables.scope.php#language.variables.scope When specifying a section, the fragment should not be shown or supplemented with a stack. And include() should always be displayed if it follows the same rules for the section. I would discuss each case in detail, but this requires a behavior specification. How can this be done? With diagrams? Tests?
fragment1
should be displayedfragment1
should be displayed - in this case, it will contain also the include()
inside the fragment1
.view_fragment
should return only fragments of content we asked for - nothing more. If the include()
is outside the fragment, then it should be ignored.From what I checked your PR is working fine. We just need some tests to cover the fixed bug.
EDIT: The tests will fail if you add fragments to different places or split a fragment into several. The current templates are primitive
<?= $this->extend('/htmx/layout') ?>
<?php $this->section('content') ?>
...
<?php $this->fragment('fragment1') ?> // in section, good. has normal data
...
<?php $this->endFragment() ?>
<?php $this->endSection() ?>
<?php $this->fragment('fragment1') ?> // out of section, bad. it may have other data that is not available without a section
...
<?php $this->endFragment() ?>
<?= $this->include('/htmx/include') ?> // the same "fragment1" may be inside or "content > fragment1"
It is very difficult to consider all cases. @kenjis or @lonnieezell can they tell me?
Okay, I get it now. Yes, the fragments implementation is very simplified. Sections are not taken into account when generating results.
Although I can't imagine a scenario where I would use the same section name in several places - I just didn't foresee that.
It is very convenient to add sections. For example, CSS, JS connection.
<?php $this->section('js') ?>
<script src="script1.js"></script>
<?php $this->endSection() ?>
// Other template with unique JS scripts
<?php $this->section('js') ?>
<script src="script2.js"></script>
<?php $this->endSection() ?>
// Output in layout
<script src="script1.js"></script>
<script src="script2.js"></script>
I keep thinking how exactly the fragment should work.
Is it worth using only one last fragment? In my case, view()->view_fragment()
does not have to output the first fragments, it should be overwritten next, not added.
It follows that endFragment()
should not output echo $contents
.
Why? It is important for HTMX to replace elements. Case. We use <div id="alerts">
in the fragment. We just pass the conditions and display the fragment <div id="alerts" hx-swap-oob="true">
. The previous fragment1 are not needed.
// $testString2 = 'Hello World';
Fragment #1 top
<?php $this->fragment('fragment_1'); ?>
<?= $testString2 ?? 'Hello' ?>, fragment1_1!
<?php $this->endFragment(); ?>
<?php $this->fragment('fragment_1'); ?>
<?= $testString2 ?? 'Hello' ?>, fragment1_2!
<?php $this->endFragment(); ?>
Fragment #1 bottom
// view('view')
Fragment #1 top
Hello World, fragment1_2!
Fragment #1 bottom
// view_fragment('fragment_1')
Hello World, fragment1_2!
// view('view')->view_fragment('view', 'fragment_1', ['testString2' => 'Goodbye World'])
Fragment #1 top
Goodbye World, fragment1_2!
Fragment #1 bottom
@datamweb Please join the discussion
Although I can't imagine a scenario where I would use the same section name in several places - I just didn't foresee that.
I should have written “fragments” and not “section” - sorry for the confusion.
Ok, I finally found some time to look at this in peace.
The way view fragments work is clear. If you use the same fragment name (example1
) multiple times in a view file, then when you use the view_fragment('file', 'example1')
, it should return content from all those fragment occurrences. Not from the first one, not the last one, but all of them (respecting the section).
The only function fragments are supposed to serve is to provide snippets of content that the developer has requested.
I will try to prepare the fixes this weekend.
Just for fragments, I don't see any cases for additions. I think it will be necessary to make unique names for the fragments, then build the entire template and at the end, based on the fragments received, replace them. You only need a rule or setting for fragments - always use the first/last one, add all the found ones or something else.
<p>
<?= fragment('post') ?>
<?= endFragment() ?>
</p>
<?= fragment('post') ?> // What can be expanded if the fragment has already been output?
<?= endFragment() ?>
In my understanding, a fragment should not have extensibility, it is not a section. The fragment must be a unique part of the section/template.
I'm very interested in the fix - I'm stuck in my own project
Fragments were never meant to be extendable.
They are simply meant to return a batch of content in between - that's all.
Unique names for fragments are something obvious - IDK if there is a scenario where I would use multiple fragments with the same name... but I will add support for them.
add in tests extra templates:
// huge_layout
Layout top
<?php echo $this->renderSection('content') ?>
<?php echo $this->include('huge_include') ?>
<?php echo $this->fragment('fragment_one'); ?>
Fragment one (from "huge_layout")
<?php echo $this->endFragment(); ?>
Layout bottom
// huge_view
<?php echo $this->extend('huge_layout') ?>
<?php echo $this->section('content'); ?>
Section (from "huge_view")
<?php echo $this->endSection(); ?>
View top
<?php $this->fragment('fragment_one'); ?>
Fragment one (from "huge_view")
<?php $this->endFragment(); ?>
# include start in "huge_view"
<?php echo $this->include('huge_include') ?>
# include end in "huge_view"
View bottom
// huge_include
Include top
<?php $this->fragment('fragment_one'); ?>
Fragment one (from "huge_include")
<?php $this->endFragment(); ?>
Include bottom
EDIT: An approximate job for many fragments. We save the places of use until output. Then, depending on the inheritance settings, we replace the unnecessary placeholders
// Before
<body>
<?= $this->fragment('post') ?>
<post />
<?= $this->endFragment() ?>
<?= $this->fragment('post') ?>
<script></script>
<?= $this->endFragment() ?>
</body>
// in progress, delete unnecessary
<body>
{{ post_fragment_KAOF34AWDGK }}
{{ post_fragment_8UJHAW657FG }}
</body>
If I understood correctly, my example should have inherited data. But I only see the first ones. I think there is a problem when using
extend()
andinclude()
. Since the normal behavior is to transfer data internally to the final templateExamples
```php class Home extends AbstractController { protected $data = []; public function index(): string { $this->data = ['foo' => 'FOO']; // 1. // return '' // . view('/bug/view1', $this->data + ['bar' => 'BAR']) // . view('/bug/view2', $this->data + ['baz' => 'BAZ']) // . view('/bug/view3', $this->data + ['too' => 'TOO']) // ; // 2. return '' . view_fragment('/bug/view1', ['fragment1'], $this->data + ['bar' => 'BAR']) . view_fragment('/bug/view2', ['fragment2'], $this->data + ['baz' => 'BAZ']) . view_fragment('/bug/view3', ['fragment3'], $this->data + ['too' => 'TOO']) . view_fragment('/bug/include', ['include'], $this->data + ['inc' => 'INC']) // . view('/bug/include', $this->data + ['inc' => 'INC']) ; } } ``` ```php // layoutfoo: = isset($foo) ? 'YES' : 'NO' ?>
bar: = isset($bar) ? 'YES' : 'NO' ?>
baz: = isset($baz) ? 'YES' : 'NO' ?>
too: = isset($too) ? 'YES' : 'NO' ?>
inc: = isset($inc) ? 'YES' : 'NO' ?>
foo: = isset($foo) ? 'YES' : 'NO' ?>
bar: = isset($bar) ? 'YES' : 'NO' ?>
baz: = isset($baz) ? 'YES' : 'NO' ?>
too: = isset($too) ? 'YES' : 'NO' ?>
inc: = isset($inc) ? 'YES' : 'NO' ?>
foo: = isset($foo) ? 'YES' : 'NO' ?>
bar: = isset($bar) ? 'YES' : 'NO' ?>
baz: = isset($baz) ? 'YES' : 'NO' ?>
too: = isset($too) ? 'YES' : 'NO' ?>
inc: = isset($inc) ? 'YES' : 'NO' ?>
foo: = isset($foo) ? 'YES' : 'NO' ?>
bar: = isset($bar) ? 'YES' : 'NO' ?>
baz: = isset($baz) ? 'YES' : 'NO' ?>
too: = isset($too) ? 'YES' : 'NO' ?>
inc: = isset($inc) ? 'YES' : 'NO' ?>
foo: = isset($foo) ? 'YES' : 'NO' ?>
bar: = isset($bar) ? 'YES' : 'NO' ?>
baz: = isset($baz) ? 'YES' : 'NO' ?>
too: = isset($too) ? 'YES' : 'NO' ?>
inc: = isset($inc) ? 'YES' : 'NO' ?>