Confusion when manipulating Structure collections

My content looks like this:

page A
  structure field
    entry 1
    ...
page B
  structure field
    entry 1
    entry 2
    ...
page C 
  structure field
    entry 1
    ...
page D
  structure field
    entry 1
    entry 2
    entry 3
...

Every ‘entry’ has an ‘uploadDate’ field.

Now I want to extract all entries from all pages into a $allEntries collection, and sort them according to the following rules:

  1. each Page contributes one entry to $allEntries
  2. when all Pages contributed an entry, then each Page can contribute an entry again (unless it has no more entries)
  3. step 2 repeats until all Pages contributed all their entries
  4. within each iteration, entries need to be sorted by ‘uploadDate’ field, ‘asc’

(think of a playlist where artists shouldn’t repeat, until all artists have a song in it; then each artist can have a second song; then a third, etc)

Using the pseudocontent above the result would be something like:

PageA entry1, PageB entry1, PageC entry1, PageD entry1 ; PageB entry2, PageD entry2 ; PageD entry3

…I separated each iteration with semicolons. As said above, within each iteration, entries should be sorted by ‘uploadDate’ field ‘asc’.

I tried to solve this with loops, but using something like:

$allEntries = new Structure();
some kind of loop
  $allEntries->add($entry);

I am getting that entries that are [0] in their respective structure fields, overwrite each other, getting only the last entry of each index among all Pages, such as, using the pseudoContent above:

PageD entry1 ; PageD entry2 ; PageD entry3

Adding the whole structure objects of each page to $allEntries $allEntries->add($myPage->myStructure()) works, but creates problems down the line when wanting to treat each entry separately and at the same level as the rest.

I am also not sure at which point should I call toStructure(), on each entry before adding it to $allEntries? on $allEntries after adding everything? on each structure field when adding it to $allEntries?

I am hitting roadblocks that I usually do not encounter when working with pages collections. I did not find too much documentation on the particularities of the Structure object either.

I would appreciate some directions, thanks :slight_smile:

In my confusion I wrote such a complicated question, let me simplify it:

I need to create a collection made of entries from several structure fields, that come from different pages.

A structure field is a field object, and when I use the ->toStructure() method it becomes a Structure collection (?) that I can deal with, Kirby style.

So I tried to do this:

    $personas = $site->children()->template("persona");
    $allWorks = new Structure();
    foreach ($personas as $persona) {
        foreach ($persona->works()->toStructure() as $work) {
            $allWorks->add($work);
        }
    };

And I would expect that to be a ‘flat’ structure object with all entries at the same level, but that is not what i get.

I get something like this:

Kirby\Cms\Structure Object
(
    [0] => 0
    [1] => 1
    [2] => 2
)

…where each index corresponds to a $persona, and contains the $works of that persona: [0] contains 1 $work, [1] contains 2 $work, and [2] contains two $work.

That isn’t flat, is nested. What am I doing wrong in my loop?

Thank you


Here is an example of the structure field yaml:

      works:
        type: structure 
        fields:
          title: 
            type: text 
            required: true
          shortdescription:
            label: Short description 
            type: textarea
          productiondate:
            label: Production Date  
            type: date
          file: 
            help: Only .ogg or .mp3
            type: files 
            max: 1   
            uploads: work
          uploaddate:
            label: Upload date 
            type: date 
            time: true
            default: now

Here is the output of dump($allWorks):

Kirby\Cms\Structure Object
(
    [0] => 0
    [1] => 1
    [2] => 2
)

Don’t do a dump($allWorks) but a `dump($allworks->toArray()) so that we see why gets created, thanks.

I was actually doing that. I added another $persona, and results are even more confusing. For this code:

<?php
$personas = $site->children()->template('persona');
$allWorks = new Structure();
foreach ($personas as $persona) {
    foreach ($persona->works()->toStructure() as $work) {
        $allWorks->add($work);
        echo($persona->title() . ' - ' . $work->title()) .  '<br />';
    }
};
dump($allWorks->toArray())
?>

This output:

Jaume Ferrete Vázquez - Mashima Love
Mariana Larraga - Moon Lambing
Mariana Larraga - Michi
Spider Anne - Suck yuyu sick
Spider Anne - Boo
Anna Moonlight - Maroon marron
Array
(
    [0] => Array
        (
            [title] => Maroon marron
            [shortdescription] => AKS askdj daskj lladks jldksajlksdajlkdajslkjdal
            [productiondate] => 
            [file] => Array
                (
                    [0] => file://xzIG1W7Sxfc5ei0P
                )

            [uploaddate] => 2024-01-19 09:00:00
            [id] => 0
            [field] => 
            [options] => Array
                (
                )

            [parent] => Kirby\Cms\Page Object
                (
                    [content] => Kirby\Content\Content Object
                        (
                            [title] => Anna Moonlight
                            [website] => https://dietz.ee/
                            [works] => - 
  title: Maroon marron
  shortdescription: >
    AKS askdj daskj lladks
    jldksajlksdajlkdajslkjdal
  productiondate: ""
  file:
    - file://xzIG1W7Sxfc5ei0P
  uploaddate: 2024-01-19 09:00:00
                            [uuid] => HDtAITSNbQr1xFmo
                        )

                    [translations] => Kirby\Cms\Collection Object
                        (
                        )

                    [children] => Kirby\Cms\Pages Object
                        (
                        )

                    [files] => Kirby\Cms\Files Object
                        (
                            [0] => anna-moonlight/water-tune.ogg
                        )

                    [id] => anna-moonlight
                    [mediaUrl] => http://localhost/~jaume/dev/aixopluc.chinocha.no/htdocs/media/pages/anna-moonlight
                    [mediaRoot] => /home/jaume/public_html/dev/aixopluc.chinocha.no/htdocs/media/pages/anna-moonlight
                    [num] => 4
                    [parent] => 
                    [slug] => anna-moonlight
                    [template] => Kirby\Template\Template Object
                        (
                            [defaultType:protected] => html
                            [name:protected] => persona
                            [type:protected] => html
                        )

                    [uid] => anna-moonlight
                    [uri] => anna-moonlight
                    [url] => http://localhost/~jaume/dev/aixopluc.chinocha.no/htdocs/anna-moonlight
                    [siblings] => Kirby\Cms\Pages Object
                        (
                            [0] => jaume-ferrete-vazquez
                            [1] => mariana-larraga
                            [2] => spider-anne
                            [3] => anna-moonlight
                            [4] => error
                            [5] => home
                        )

                )

            [siblings] => Kirby\Cms\Structure Object
                (
                    [0] => 0
                )

        )

    [1] => Array
        (
            [title] => Boo
            [shortdescription] => ma boo boo boo
            [productiondate] => 
            [file] => Array
                (
                    [0] => file://a0daZdwMvAiZ7a1H
                )

            [uploaddate] => 2024-01-18 21:50:00
            [id] => 1
            [field] => 
            [options] => Array
                (
                )

            [parent] => Kirby\Cms\Page Object
                (
                    [content] => Kirby\Content\Content Object
                        (
                            [title] => Spider Anne
                            [website] => https://noguerasblanchard.com/en
                            [works] => - 
  title: Suck yuyu sick
  shortdescription: >
    Suck sick yuyu, you looming do lu.
    Lounge in cocoon, bit bark bow low goo.
  productiondate: ""
  file:
    - file://BQq2y0IgUwm61WYM
  uploaddate: 2024-01-16 21:30:00
- 
  title: Boo
  shortdescription: ma boo boo boo
  productiondate: ""
  file:
    - file://a0daZdwMvAiZ7a1H
  uploaddate: 2024-01-18 21:50:00
                            [uuid] => 7sQeCydP8fr5Iw1n
                        )

                    [translations] => Kirby\Cms\Collection Object
                        (
                        )

                    [children] => Kirby\Cms\Pages Object
                        (
                        )

                    [files] => Kirby\Cms\Files Object
                        (
                            [0] => spider-anne/amb_bigfoot_backing_part_03_09.mp3
                            [1] => spider-anne/joies.mp3
                        )

                    [id] => spider-anne
                    [mediaUrl] => http://localhost/~jaume/dev/aixopluc.chinocha.no/htdocs/media/pages/spider-anne
                    [mediaRoot] => /home/jaume/public_html/dev/aixopluc.chinocha.no/htdocs/media/pages/spider-anne
                    [num] => 3
                    [parent] => 
                    [slug] => spider-anne
                    [template] => Kirby\Template\Template Object
                        (
                            [defaultType:protected] => html
                            [name:protected] => persona
                            [type:protected] => html
                        )

                    [uid] => spider-anne
                    [uri] => spider-anne
                    [url] => http://localhost/~jaume/dev/aixopluc.chinocha.no/htdocs/spider-anne
                    [siblings] => Kirby\Cms\Pages Object
                        (
                            [0] => jaume-ferrete-vazquez
                            [1] => mariana-larraga
                            [2] => spider-anne
                            [3] => anna-moonlight
                            [4] => error
                            [5] => home
                        )

                )

            [siblings] => Kirby\Cms\Structure Object
                (
                    [0] => 0
                    [1] => 1
                )

        )

)

…now I would say entries are perhaps overwriting each other when I use $allWorks->add() as only the two last ones are on the array. And since it seems that the Structure collection works by index.

Hello, do you have any insights, @texnixe ? I am frankly lost.

If I look into the collection ->add() method code, I see it uses the id of the element that it tries to add to the data array, as index(?), see this line …and from the dumped array I also see that the ids of the structure field entries appear to be their index in the parent structure field. So each first entry of each structure field, has an id of 0, each second entry has an id of 1, etc.

That would explain why they seem to overwrite each other.

But shouldn’t it be simple to aggregate Structure objects from different pages structure fields into a new Structure collection? Is the Structure collection not supposed to be used like this?

Thank you.

Yes, that should be easy, and your code is the same that I posted somewhere else which worked at the time.

Sorry for getting back to you late, I originally read your post late at night on Thursday, when I was too tired to answer, then forgot about it.

Let me do a quick test.

1 Like

You can use append() instead:

use Kirby\Cms\Structure;
use Kirby\Uuid\Uuid;

$structure = new Structure();
foreach ($page->children()->listed() as $child) {
    $items = $child->works()->toStructure();
        foreach ($items as $item) {
            $structure->append(Uuid::generate(), $item);
        }
}
foreach ($structure as $item) {
    echo $item->title();
    echo $item->shortdescription();
}

No need to apologize, many people, many questions, your help is always much appreciated :slight_smile:

So, I see that append() allows specifying the index, and for that you are producing an uuid to ensure uniqueness.

Thank you very much

Although I am still annoyed at the add() method behavior for structure, perhaps some change introduced on v4 ? should I fill in an issue? not sure if this qualifies.

Thanks again

Didn’t work when I tested this in v3, either. So not a regression, at least not from recent v3 versions. But my guess is that it worked at some point in the past.

On a side note, add() also seems to work fine when adding an id field to a structure and filling it with a unique value.

1 Like