Help to update content of a structure with kirby?

Hi,

In my blueprint i have a structure to manipulate and modify from a plugin :

----

Maillingblock:

- 
  mailobject: My first email
  datesent: 2023-11-04
  sentdate: ""
- 
  mailobject: My second email
  datesent: 2023-11-11
  sentdate: ""

----

Later i’m interested to filter this structure using filterby to see if today is the day to send a mail, but in a first time i try to understand how i will update the sentDate fields with current time.

In the plugin that manage my email campaign with an exemple of filter on DateSent field :

 'action' => function () use ($kirby){
            $eventpages = $kirby->site()->pages()->find("evenements")->children();

            foreach($eventpages as $event){

                $mblocks =$event->Maillingblock()->toStructure();

                // update Field if Date is superior to 2023-10-10
                $not_empty_block = $mblocks->map(function($x) {
                    if (V::date($x->content()->DateSent(), '>=', '2023-10-10') ){
                        $x->content()->update(['SentDate' => time()]);
                    }
                    return $x;
                });

                 $event = $event->update(['maillingBlock' => $not_empty_block]);
            }
            return  [$event];
        }

I run the plugin, by calling the defined route (http://localhost:8000/evenements/mailling) but nothing happen in the structure when i refresh the corresponding blueprint page …

I don’t understand well how updating() works, i already read this doc :

Thanks,
SR

You can only update a page. So you usually get an array of structure items (using yaml instead of toStructure(), then you modify the array items, and then update the page! with the yaml encoded array (Data::encode($array, ‘yaml’)`).

Ok, thx, i see @texnixe !

In my exemple, i have a foreach on children() of site()->pages()->find("evenements") pages, so $even is a $page no ?

foreach($eventpages as $event) ..
 $eventpages = $kirby->site()->pages()->find("evenements")->children();

Is it also possible to use filter / filterBy without using Structure ?

Perhaps it’s better to filter structure then transform/modify yaml then reencode ?

I try another things based on one of your answer (How to update a structure via the API?) on the forum, just to test an update without changing content :

Kirby::plugin('idees/mailling', [
     'routes' => function($kirby) {
     return [
     [
      'pattern' => '/evenements/mailling',
      'action' => function () use ($kirby){

           $eventpages = $kirby->site()->pages()->find("evenements")->children();

            $result = array();

            foreach($eventpages as $event){

                $mblocks =$event->Maillingblock()->toYaml();

               // just to test, filtering later
                $not_empty_block = $mblocks->map(function($x) {
                    return $x;
                });
                $data = Data::encode($not_empty_block, 'yaml');
                array_push($result,$data);         
      }
          return [$result];
        }

But i have a php error returned by kirby, i miss something @texnixe ?

**Fatal error**: Allowed memory size of 134217728 bytes exhausted (tried to allocate 249856 bytes) in **/home/reyman/Projets/Guix-ified/webdev/site-umr-idee/kirby/dependencies/spyc/Spyc.php** on line **251**

**Fatal error**: Allowed memory size of 134217728 bytes exhausted (tried to allocate 122880 bytes) in **/home/reyman/Projets/Guix-ified/webdev/site-umr-idee/vendor/filp/whoops/src/Whoops/Util/SystemFacade.php** on line **77**

This cannot work, $mblocks is an array, not a collection, so you have to use array_map() and cannot call a collection method.

Hum, this is strange, i actually use kirby 4 beta 3 and when i run this in the same context (foreach $eventpages as $event) :

 $mblocks =$event->Maillingblock()->toYaml();

                $not_empty_block = $mblocks->array_map(function($x) {
                    if (V::date($x['DateSent'], '>=', '2023-11-6')){
                        $x['SentDate'] = time();
                    }else
                    {
                         $x['SentDate'] = "";
                    }
                    return $x;
                });

                array_push($result,$not_empty_block->toArray());

I have this result :

[[{"maillingblock":"- \n  mailobject: test 1\n  datesent: 2023-11-05\n  sentdate: \"\"\n- \n  mailobject: test 2\n  datesent: 2024-11-05\n  sentdate: \"\""},{"maillingblock":""}]]
  • When i convert into yaml with the converting from $not_empty_block recognized as a Kirby->Content-Field class (using get_class php function ) to an Array using toArray(), the encoding into yaml works :
array_push($result,Yaml::encode($not_empty_block->toArray()));
  • But when i try to convert it into yaml without converting toArray(), it failed with a memory error on sycp, even with unlimited memory :
array_push($result,Yaml::encode($not_empty_block));

I have this with php -d memory_limit=-1 :

  • Maximum execution time of 30 seconds exceeded

And without this option, an error of memory limit :

**Fatal error**: Allowed memory size of 134217728 bytes exhausted (tried to allocate 249856 bytes) in **/home/reyman/Projets/Guix-ified/webdev/site-umr-idee/kirby/dependencies/spyc/Spyc.php** on line **251**

**Fatal error**: Allowed memory size of 134217728 bytes exhausted (tried to allocate 122880 bytes) in **/home/reyman/Projets/Guix-ified/webdev/site-umr-idee/vendor/filp/whoops/src/Whoops/Util/SystemFacade.php** on line **77**

Is it a bug ?
Why i need converting toArray ?

@texnixe Ok i found two errors in my code, :

(a) First, i call the bad method :

 $mblocks =$event->Maillingblock()->toYaml()

is different from

 $mblocks =$event->Maillingblock()->yaml()

I didn’t found this yaml() call in the API documentation in Structure / StructureObject : Objects | Kirby CMS

Do you have a link for this method somewhere @texnixe ?

(b) my call to array_map is badly written, and fail silently … this code works now

  $not_empty_block = array_map(function($x) {
                    if (V::date($x['datesent'], '>=', '2023-11-6')){
                        $x['sentdate'] = time();
                    }else
                    {
                         $x['sentdate'] = "";
                    }
                    return $x;
                }, $mblocks);

                $dataToUpdate = Yaml::encode($not_empty_block);
                array_push($result,$dataToUpdate);

But the update of $event (the current page that contain the structure to update) continue to failed :

$event = $event->update(['maillingblock'], $dataToUpdate);

Any idea ?

Update 1

Found, i’m so silly !

This is not

$event = $event->update(['maillingblock'], $dataToUpdate);

but

$event = $event->update(['maillingblock' => $dataToUpdate]);

This is so complicated when things fail silently, why the first syntax didn’t crash !?

I’m interested to know more about the location of yaml() method for StructureObject if you a link @texnixe …

There are some info like manipulation/update of Structure that miss on the doc, thanks a lot for your premium help @texnixe , and sorry for all my mistake. The fact that lot of syntax mistake fail silently complexify the debug.

There were several issues with your code, some you have already found. But since it is not complete, I don’t really know what you are doing.

For example

Here, you yaml encode, and then you add this yml encoded stuff to an $result array, but I don’t know why you have this result array at all.

Sorry for that, this is because i develop this code into a plugin, calling /evenements/mailling to see the $result :

<?php

Kirby::plugin('idees/mailling', [
     'routes' => function($kirby) {
     return [
     [
      'pattern' => '/evenements/mailling',
      'action' => function () use ($kirby){
            $eventpages = $kirby->site()->pages()->find("evenements")->children();

            $result = array();

            foreach($eventpages as $event){

                //WORKING WITH YAML

                $mblocks =$event->Maillingblock()->yaml();

                $not_empty_block = array_map(function($x) {
                    if (V::date($x['datesent'], '>=', '2023-11-6')){
                        $x['sentdate'] = time();
                    }else
                    {
                         $x['sentdate'] = "";
                    }
                    return $x;
                }, $mblocks);

                $dataToUpdate = Yaml::encode($not_empty_block);
                $event = $event->update(['maillingblock' => $dataToUpdate]);
                array_push($result,$dataToUpdate);
      }

          return [$result];
        }
    ]
    ];
    }

]
);

I develop this plugin to send email based on structureField stored in each event page.

A cron job (using the website https://cron-job.org/en/) call this script / url each night to detect if email need to be sent (using filter on DateSent field) and update the subfield SentDate of my structure when it’s done.

Hope this is more clear @texnixe

Ok, another issue here is that $page->update() needs authentication, otherwise, it will fail (and usually throw an error).