Recommended Posts

Hello there!

I'd love to see more array operation functions such as map/reduce. There are already a few helpful functions there like pop, shift, etc.

I find myself turning pageArrays into arrays, do array_map or similar and create pageArrays again from that data.

For Processwire, it would be really helpful to perform forEach operations more comfortably.

E.g.

<?php
$allTitles = $pages->map(function($page){return $page->title});

// vs traditionally:

$allTitles = [];
foreach($pages as $page) {
	array_push($allTitles, $page->title);
}

$pages->reduce would be really helpful too. This would avoid many in-between variables when calculating sums of fields stored in individual pages.

 

Thank you in advance :)

Best,
Martin

  • Like 1

Share this post


Link to post
Share on other sites
bernhard    1,313

what about this?

<?php
$allTitles = $yourPageArray->each('title');

// or if it was more complex
$allTitles = $yourPageArray->each(function($page) {
  return "{$page->forename} {$page->surname}";
}

you can also add your own methods via hooks:

  $wire->addHookMethod('WireArray::test', function($event) {
    $arr = $event->object;
    $out = [];
    foreach($arr as $item) $out[] = 'testing page ' . $item->id;
    $event->return = $out;
  });

59b6439d01eb4_2017-09-1110_03_51-EditPage_Testhrd-360-neu_Chakaaa!360.hrdiamonds_com.png.c65551ea834c3c4879a354c5125442dc.png

  • Like 2

Share this post


Link to post
Share on other sites
abdus    596

Here are my generic versions

WireArray::map

wire()->addHookMethod('WireArray::map', function (HookEvent $e) {
    $func = $e->arguments(0);
    if (!is_callable($func)) throw new WireException('first argument must be a callable function');

    $mapped = array_map($func, $e->object->getArray());
    $e->return = $mapped;
});

WireArray::reduce

wire()->addHookMethod('WireArray::reduce', function (HookEvent $e) {
    $func = $e->arguments(0);
    $initial = $e->arguments(1) ?? [];
    if (!is_callable($func)) throw new WireException('first argument must be a callable function');

    $reduced = array_reduce($e->object->getArray(), $func, $initial);
    $e->return = $reduced;
});

WireArray::forEach

wire()->addHookMethod('WireArray::forEach', function (HookEvent $e) {
    $func = $e->arguments(0);
    if (!is_callable($func)) throw new WireException('first argument must be a callable function');

    $foreached = [];
    foreach ($e->object as $i => $item) $foreached[] = $func($item, $i);
    $e->return = $foreached;
});

Tests

$mapped = $pages->find('id>0, parent=2')->map(function($page) {
    return [
        'title' => $page->title,
        'id' => $page->id
    ];
});

$reduced = $pages->find('template=post')->reduce(function($carry, $item){
    $carry[] = $item->id;
    return $carry;
}, []);

$foreached = $pages->find('template=post')->forEach(function($item){
    echo $item->id . '<br>';
});

dump($mapped);
dump($reduced);
dump($foreached);

Which outputs

array (4)
    0 => array (2)
        title => "Pages" (5)
        id => 3
    1 => array (2)
        title => "Setup" (5)
        id => 22
    2 => array (2)
        title => "Modules" (7)
        id => 21
    3 => array (2)
        title => "Access" (6)
        id => 28

array (8)
    0 => 1024
    1 => 1026
    2 => 1028
    3 => 1031
    4 => 1033
    5 => 1058
    6 => 1062
    7 => 1065

1024
1026
1028
1031
1033
1058
1062
1065

array (8)
    0 => null
    1 => null
    2 => null
    3 => null
    4 => null
    5 => null
    6 => null
    7 => null
    
29.59ms, 0.06MB

 

  • Like 4

Share this post


Link to post
Share on other sites
netcarver    1,877
5 hours ago, Martin Muzatko said:

$pages->reduce would be really helpful too. This would avoid many in-between variables when calculating sums of fields stored in individual pages.

You could also try ersch's PagesSum module for this aspect.

 

  • Like 1

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now


  • Recently Browsing   0 members

    No registered users viewing this page.

  • Similar Content

    • By Davidov
      Good Day!
      I am a beginer of processwire project. Thanks developers for your great work. this CMS is very Good!
      I have a question: how get Pageimage object of PageArray from "Page" (PageArray) field type?
      I have too tamplates: affiliates and their teachers. The template of affiliates have a field "teachers_list" wich is "Page" (PageArray) type.
      When I vaffiliate teachers in a cycle, I can not access the teacher photo object and change its size.   I get an error returning: " Fatal error: Call to a member function maxWidth() on null ". When i trying get URL attribute : $teacherItem->teacher_photo->url, i receive message: " Trying to get property of non-object ".   But this code works: $teacherItem->teacher_photo["url"].   The print_r function outputs the following information: "ProcessWire \ Pageimage Object ([changes] => Array ([0] => formatted) [hooks] => Array ([Pageimage :: pim2Load] => PageImageManipulator02-> getPageImageManipulator02 () in PageImageManipulator02.module ) [Data] => Array ([basename] => p16.jpg [description] => .... - ..... [tags] => [formatted] => 1 [modified] => 1487079115 [created ] => 1487079115))".   my PHP code: foreach ($page->teacher_list as $teacherItem): $out .= " <tr> <td class=\"alignTop\"> /* !!! my truble */ <img src=\"{$teacherItem->teacher_photo->maxWidth(250)->url}\" /> /* !!! my truble */ </td> <td class=\"alignTop\"> <div class=\"teach_style12\"> <strong>$teacherItem->fio</strong><br/> $teacherItem->degree<br/> $teacherItem->headline_detail </div> <div class=\"teach_style9\"> $teacherItem->body </div> </td> </tr>"; endforeach; Please, help me. Where is my error?
       
    • By Michael Steinmann
      Hello everyone,
      i guess my php knowledge is not good enough to find a solution for the following problem:
      I'm building a website where i have projects. Each project has tags like "webdesign, responsive, cms, print, flyer" etc. At the end of a project i want to recommend other projects, which have similar tags. I want to limit the recommendations to three other projects sorted by the hightest amount of same tags.
      This is how far i got:
      I'm using
      <?php $interessantes = $pages->find("tags=$page->tags, id!=$page->id"); ?> to find other projects with the same tags, excluding the page i'm already on.
      Then i'm using three foreach-functions to go through the projects i found, the tags they have and compare them with the tags of the project i'm looking at. If i have two identical tags, i count up a variable.
      <?php // Projects i have found foreach($interessantes as $interessant): $i = 0; // Tags of the projects i have found foreach($interessant->tags as $tag): // Tags of the project i'm looking at foreach($page->tags as $tagreferenz): if($tag == $tagreferenz): $i++; endif; endforeach; endforeach; endforeach; ?> You can see what it looks like in the screenshot with a bit of HTML. I marked the tags of the current project green and the identical tags of other projects red with the amount of hits below. So in this example i would want to have three projects with three similar tags and get rid of those with only two and one.

      I guess i have to put my pages into an array (with the number of hits?), sort them and echo them with "limit=3"? Unfortunately i have no idea how to do this. You probably have an even better/shorter solution. Links to other topics are welcome to and i'll try to get my head around it.
      If you need further explanation, i'll try my best.
      Best regards
    • By beto
      I can't add a new value to a custom PageArray field  for my user.
       
      However, when I create a new user, I CAN add the new PageArray value:
       
      I need help. Thank you very much.
       
    • By ---
      I've got this code to fetch all pages:
      /** @var PageArray $pages */ $pages = $this ->wire('pages') ->find(sprintf( 'has_parent!=2,id!=2|7,status<%s', Page::statusTrash )); With this I fetch all pages except admin, but that includes the 404 page as well. Is there a way to exclude pages like the 404 page from the result? Or maybe loop through the result set to check for the pages response code (without curl that is)?
      I want to avoid filtering the 404 page by ID if possible.
    • By bmacnaughton
      I have a situation where a pagearray appears to lose its sort order.
      1. template xyzzy.php fetches a pagearray with code similar to:
      // in an external include file function get_pages($selector) { $found = wire('pages')->find($selector); wire('log')->save('fubar', count($found)); return $found; } // in the template xyzzy $pa = get_pages($some_selector); $pa->sort('-timestamp'); 2. main.inc is appended to the template. in main.inc an additional file is included, './layouts/xyzzy.php'
      3. './layouts/xyzzy.php' then references $pa as such:
      <? foreach($pa as $p): ?> // do stuff with $p // log for debugging wire('log')->save('xyzzy', $p->name); <? endforeach ?> 4. The $pa that './xyzzy.php' sees is sorted while the $pa that './layouts/xyzzy.php' sees is NOT sorted. It seems like the PageArray/WireArray got copied at some point but the './layouts/xyzzy.php' file shouldn't have been included until 'main.inc' is appended.
       
      What am I missing?