Jump to content

bernhard

Members
  • Posts

    4,085
  • Joined

  • Last visited

  • Days Won

    144

Everything posted by bernhard

  1. yeeha!! 😎 <?php /** * Center Buttons * @return Buttons */ public function getButtonsCenter() { $buttons = parent::getButtonsCenter(); $buttons->add([ 'name' => 'markClaimed', 'icon' => 'check', 'tooltip' => 'Mark selected items as claimed', 'hidden' => '!selected', 'appendMarkup' => '<div id=markClaimedConfirm hidden>...</div>', 'callback' => [ 'name' => 'sendIDs', 'confirmmarkup' => '#markClaimedConfirm', 'loading' => 'Saving items...', 'reload' => true, 'execute' => function($input, self $grid) { $ids = $this->wire->sanitizer->intArray($input->ids); $note = $this->wire->sanitizer->text($input->note); foreach($this->wire->pages->findMany(["id" => $ids]) as $p) { $p->setAndSave(Effort::field_claimed, 1); $p->setAndSave(Effort::field_claimedwith, $note); $grid->sse("Saved page $p"); sleep(1); // just for the screencast } $grid->sseDone(); return ['success' => true]; }, ], ]); return $buttons; }
  2. Ok I did some more testing and found out that using str_pad is the most reliable solution. At least in the environments I tested (laragon, DDEV, ubuntu+apache). So I can't say anything about ob_implicit_flush()
  3. A user in another forum found a solution!!! <?php header("Cache-Control: no-cache"); header("Content-Type: text/event-stream"); $i = 0; while(true) { $i++; echo "data: value of i = $i\n\n"; echo str_pad('',8186)."\n"; flush(); if(connection_aborted()) break; sleep(1); } Reading the manual about flush() finally broucht me to the correct settings for my setup: <?php header("Cache-Control: no-cache"); header("Content-Type: text/event-stream"); @apache_setenv('no-gzip', 1); @ini_set('zlib.output_compression', 0); @ini_set('implicit_flush', 1); ob_implicit_flush(1); $i = 0; while(true) { $i++; echo "data: value of i = $i\n\n"; flush(); if(connection_aborted()) break; sleep(1); } I've tried several settings before regarding gzip, but nothing worked. For me the ob_implicit_flush(1) made the difference 🙂 https://www.php.net/manual/de/function.flush.php
  4. data: value of i = 1 array(1) { [0]=> array(7) { ["name"]=> string(22) "default output handler" ["type"]=> int(0) ["flags"]=> int(112) ["level"]=> int(0) ["chunk_size"]=> int(4096) ["buffer_size"]=> int(8192) ["buffer_used"]=> int(22) } } data: value of i = 2 array(0) { } data: value of i = 3 array(0) { } data: value of i = 4 array(0) { } data: value of i = 5 array(0) { } data: value of i = 6 array(0) { } data: value of i = 7 array(0) { } data: value of i = 8 array(0) { } data: value of i = 9 array(0) { }
  5. Hi @3fingers thx but I think the problem is my server setup and I'm not good at debugging network stuff. See http://sse.baumrock.com/sse3.html where I have this code: <?php date_default_timezone_set("America/New_York"); header("Content-Type: text/event-stream"); $i = 0; while(true) { $i++; // manual limit of 10 runs for development if($i>=10) return; echo "data: value of i = $i\n\n"; while (ob_get_level() > 0) ob_end_flush(); flush(); if(connection_aborted()) break; sleep(1); } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <h1>Open DevTools Console + Network Tab!</h1> <script> const evtSource = new EventSource("sse.php", { withCredentials: true } ); evtSource.onmessage = function(event) { console.log(event.data); } </script> </body> </html> It works locally: https://calip.io/HkCWbYAB#ueAgNM5v But it does not work on my server: https://calip.io/DzhmJQo2#4mfu1aP6 I bet this has something to do with gzip but I can't make it work 😞 I thought maybe you guys know more about networking and http/tcp stuff and can help me debugging or making it work...
  6. Thx @netcarver sorry I've quoted @kongondo and linked you in the same sentence 😉 http://sse.baumrock.com/sse2.html --> the event is received every 10s which is wrong as far as I understood how SSE should work. I'd expect a console.log() happen each second and have one open stream as long as I click on "close the connection"
  7. Hi community, last week I've tried to get PHP SSE working. Unfortunately without success. When using laragon it works, but on my DDEV setup and also on my live server it does not. I think there is some kind of compression and/or proxying going on, but I don't know how to debug or disable that. @kongondo and @netcarver have mentioned SSE is "is so simple it is unbelievable at first." Maybe you can help me? This is what I've tried: <?php header("Cache-Control: no-cache"); header("Content-Type: text/event-stream"); $i = 0; while(++$i<=10) { echo "event: ping\n"; $curDate = date(DATE_ISO8601); echo 'data: {"time": "' . $curDate . '"}'; echo "\n\n"; file_put_contents(__DIR__."/dump.txt", "triggered@$curDate\n", FILE_APPEND); ob_end_flush(); flush(); if ( connection_aborted() ) break; sleep(1); } <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title> </head> <body> <script> const evtSource = new EventSource("sse.php", { withCredentials: true } ); evtSource.onmessage = function(event) { console.log(event.data); } </script> </body> </html> The file_put_contents works as expected, just the javascript does not get the messages from SSE: The eventstream is sent after 10 seconds at once and not on each event: Then the request is sent again and the same process starts from the beginning... You can try the example here: http://sse.baumrock.com/sse.html I'd be very happy if anybody could help me making this work 🙂
  8. I came to this thread by coincidence: It was very popular back then. But I've never heard of anybody using dynamic roles over the last few years. Is anybody using it and want to share the "why" and "how"? 🙂
  9. You might want to add an additional if($page->template != 'your-pagereference-template') return; inside the hook if you do not want to set all languages active globally on the site...
  10. Does it work if you place this hook in site/ready.php? <?php // set all languages active automatically $wire->addHookAfter('Pages::added', function($event) { $page = $event->arguments(0); foreach($this->wire->languages as $lang) { if($lang->isDefault()) continue; $page->set("status$lang", 1); } $page->save(); });
  11. Thx for that example. I understand now. <?php // migrate field content only if the address field exists if($rm->fields->get('address')) { // first we make sure the fields exist $rm->createField('foo', 'text'); $rm->createField('bar', 'text'); $rm->createField('baz', 'text'); // then we make sure they are added to xyz template $rm->addFieldsToTemplates(['foo','bar','baz'], 'xyz'); // then we migrate data foreach($pages->find('template=xyz,address!=') as $p) { $parts = ...; // split address into parts $p->of(false); $p->foo = $parts[0]; $p->bar = $parts[1]; $p->baz = $parts[2]; $p->save(); } // then we delete the obsolete field $rm->deleteField('address'); } // then we use the existing migration config for future use // so you can easily add other stuff (like whatsoever field) $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], 'whatsoever' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], 'whatsoever' => [ 'fields' => ['whatsoever'], ], ], ]); If you are inside a module that uses a migrate() method to migrate data this could easily been refactored to this: <?php class MyModule ... { public function migrate() { $rm = $this->wire->modules->get('RockMigrations'); $this->migrateAddressData(); $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], 'whatsoever' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], 'whatsoever' => [ 'fields' => ['whatsoever'], ], ], ]); } public function migrateAddressData() { // if the address field does not exist any more // we can exit early as we have nothing to do if(!$rm->fields->get('address')) return; // first we make sure the fields exist $rm->createField('foo', 'text'); $rm->createField('bar', 'text'); $rm->createField('baz', 'text'); // then we make sure they are added to xyz template $rm->addFieldsToTemplates(['foo','bar','baz'], 'xyz'); // then we migrate data foreach($pages->find('template=xyz,address!=') as $p) { $parts = ...; // split address into parts $p->of(false); $p->foo = $parts[0]; $p->bar = $parts[1]; $p->baz = $parts[2]; $p->save(); } // then we delete the obsolete field $rm->deleteField('address'); } } This is one of the situations that are not possible using YAML of course 🙂 But the "migrateAddressData" could be done in PHP while the migrate() could migrate YAML data still.
  12. Exactly. It's even named like this: migrate($config) https://github.com/BernhardBaumrock/RockMigrations/blob/db4d300b4369863d41003f5c668b7ecaf2f19b5d/RockMigrations.module.php#L2693 Sorry, I don't understand. Note that I have no experience with multiplier fields. Maybe you can give me another example?
  13. Migration 21-11 (add foo field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo'], ], ], ]); Migration 21-12 (add bar field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar'], ], ], ]); Migration 22-01 (add baz field) <?php $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], 'baz' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar', 'baz'], ], ], ]); RockMigrations works in a way that no matter how often you run the migration the config will be applied and the system will result in the same config each time. I know this is a totally different concept than you are using in your migrations module but it has turned out to be extremely easy to use and it works well. In the example above it does not matter if you jump from 21-11 to 21-12 and then to 22-01 or if you go directly from 21-11 to 22-01. Or you could even start with 22-01 and nothing else before. That's easy as long as you add things to the system. Removing things is a little different, but it's also easy: 22-02 (remove baz field) <?php $rm->removeField('baz'); $rm->migrate([ 'fields' => [ 'foo' => [...], 'bar' => [...], ], 'templates' => [ 'xyz' => [ 'fields' => ['foo', 'bar'], ], ], ]); Reverting things it a totally different topic! 22-01 --> 21-11 would not really be possible using RockMigrations. Though you can think of 22-02 as a "revert migration" that does exactly what a reversion would do. But if one does not like that concept they could also use RockMigrations in a way your module works. In my experience this makes migrations just a lot more complex while adding things into a php array is cake. I've never had any problems over the last few years with my concept 🙂
  14. thx! I'm thinking about it. But I think not to the current version. RockMigrations has evolved over the last years and it's time to refactor and clean up and that would be a good opportunity. What I'd like to know of you guys is why everybody seems to be so excited about YAML? Is it about the YAML thing or is it about the recorder? I'm asking because YAML would really be a drawback IMHO. What I think would be much better is to have a regular PHP file that returns a simple array. That's almost the same as a YAML file but you can do additional things if you want or need. See this example: <?php namespace ProcessWire; /** @var RockMigrations $rm */ return [ 'fields' => [ 'foo' => [ 'type' => $wire->languages ? 'textlanguage' : 'text', ], ], 'templates' => [ 'demo' => [ 'tags' => RockMails::tags, 'fields-' => [ 'title', 'foo', ], ], ], ]; That migration file would add a "foo" field and depending on the system make this field single or multi-language. That would be just one example which would not be possible using YAML syntax. Another thing is using class constants. Possible in PHP (see RockMails::tags in the example above), not possible in YAML. I'm really curious what it is really about, thx.
  15. Well that's two different dumps... one is dumping the array and one is dumping an object that has an array inside the data property! d($config->paths); d($config->paths->data); Personally I think that behaviour is good 🙂
  16. Ok strange because I tested it today myself and it just worked for 110 items, so I thought it works as expected?! 🤷‍♂️
  17. Hi and welcome to the forum / PW 🙂 Have a look at https://processwire.com/modules/tracy-debugger/ that makes your life a lot easier!
  18. I think I don't agree with you here. Could you please explain that in detail? I'm not sure I understand. What you are asking for is exactly what I'm showing in the video?!
  19. Side note @ryan it would be nice if you could add relevant keywords to the title of new news or blog posts. This makes it easier to find information when you are searching for it weeks or months later ("weekly update 14.1." is not nearly as helpful as "weekly update find raw parents, sanitizer float" in a search result) +1 for better version control support. I've not built RockMigrations just for fun 😁
  20. Hi @Richard Jedlička there's one slash too much on line 134 🙂 PS: If it is easy to implement a "save + reload" button would be nice to have in the modal 🙂
×
×
  • Create New...