BitPoet Posted March 21, 2018 Posted March 21, 2018 (edited) Not sure where the best place for this is, but I felt like sharing a little snippet for site/ready.php I wrote that creates a PageArray::groupBy method: <?php /** * * Adds a groupBy method to all PageArray instances. * * Returns a nested array, with the values of the page properties whose names * were passed as arguments as the keys. * * Usage: * ====== * * $grouped = $mypagearray->groupBy(field1 [, field2 ...] [, mutator_function]); * or * $grouped = $mypagearray->groupBy(mutator_function); * * Example: * ======== * * $mypagearray = $pages->find("template=blog-post, sort=year, sort=month"); * $grouped = $mypagearray->groupBy("year", "month"); * * foreach($grouped as $year => $monthgroup) { * echo "<div class='year'><h2>$year</h2>" . PHP_EOL; * echo "\t<ul class='month'>" . PHP_EOL; * * foreach($monthgroup as $month => $mypages) { * echo "\t\t<li><h3>$month</h3>" . PHP_EOL; * * echo "\t\t\t<ul class='post'>" . PHP_EOL; * * foreach($mypages as $post) { * echo "\t\t\t\t<li><a href='{$post->url}'>{$post->title}</a></li>" . PHP_EOL; * } * * echo "\t\t\t</ul>\n" . PHP_EOL; * echo "\t\t</li>\n" . PHP_EOL; * } * * echo "\t</li>" . PHP_EOL; * echo "</ul>" . PHP_EOL; * } * * Example Output: * =============== * * <div class='year'><h2>2016</h2> * <ul class='month'> * <li><h3>1</h3> * <ul class='post'> * <li><a href='/grouptest/grouptest-10/grouptest-10-10/'>Group Test 10 10</a></li> * <li><a href='/grouptest/grouptest-6/grouptest-6-10/'>Group Test 6 10</a></li> * <li><a href='/grouptest/grouptest-10/grouptest-10-12/'>Group Test 10 12</a></li> * <li><a href='/grouptest/grouptest-1/grouptest-1-12/'>Group Test 1 12</a></li> * <li><a href='/grouptest/grouptest-5/grouptest-5-3/'>Group Test 5 3</a></li> * <li><a href='/grouptest/grouptest-10/grouptest-10-4/'>Group Test 10 4</a></li> * <li><a href='/grouptest/grouptest-3/'>Group Test 3</a></li> * <li><a href='/grouptest/grouptest-6/grouptest-6-4/'>Group Test 6 4</a></li> * <li><a href='/grouptest/grouptest-10/grouptest-10-7/'>Group Test 10 7</a></li> * </ul> * * </li> * * <li><h3>2</h3> * <ul class='post'> * <li><a href='/grouptest/grouptest-5/grouptest-5-10/'>Group Test 5 10</a></li> * <li><a href='/grouptest/grouptest-3/grouptest-3-7/'>Group Test 3 7</a></li> * <li><a href='/grouptest/grouptest-9/grouptest-9-5/'>Group Test 9 5</a></li> * <li><a href='/grouptest/grouptest-7/grouptest-7-12/'>Group Test 7 12</a></li> * <li><a href='/grouptest/grouptest-3/grouptest-3-11/'>Group Test 3 11</a></li> * <li><a href='/grouptest/grouptest-9/grouptest-9-11/'>Group Test 9 11</a></li> * </ul> * * </li> * * <li><h3>3</h3> * <ul class='post'> * <li><a href='/grouptest/grouptest-7/grouptest-7-10/'>Group Test 7 10</a></li> * <li><a href='/grouptest/grouptest-12/grouptest-12-12/'>Group Test 12 12</a></li> * <li><a href='/grouptest/grouptest-11/grouptest-11-5/'>Group Test 11 5</a></li> * </ul> * * </li> * * <li><h3>4</h3> * <ul class='post'> * <li><a href='/grouptest/grouptest-8/grouptest-8-3/'>Group Test 8 3</a></li> * <li><a href='/grouptest/grouptest-12/grouptest-12-6/'>Group Test 12 6</a></li> * </ul> * * </li> * * </li> * </ul> * * IMPORTANT! * ========== * * Your PageArray needs to be sorted by the fields you group by, or your return array will be an * unorderly mess (the grouping is still correct, but the order of keys is arbitrary). * * Mutator Function: * ================= * * Instead of just reading properties from the page, you can also pass a mutator function * to groupBy. It gets passed the page object as its first arguments and any optional property * names after that. * * This might come in handy if you want to group by year and month but only have a single * DateTime field. You can then use a grouping function like this: * * $blogposts = $pages->find("template=blog-post, sort=created"); * $grouped = $blogposts->groupBy(function($pg) { * return array(strftime('%Y', $pg->created), strftime('%m', $pg->created)); * }); * */ wire()->addHook("PageArray::groupBy", function(HookEvent $event) { $out = array(); $args = $event->arguments(); if(count($args) == 0) throw new InvalidArgumentException("Missing arguments for function PageArray::groupBy, at least 1 required!"); $last = count($args) - 1; $fnc = is_string($args[$last]) ? FALSE : array_pop($args); foreach($event->object as $pg) { if($fnc) { $props = call_user_func_array($fnc, array_merge(array($pg), $args)); } else { $props = array_map(function($propname) use($pg) { return $pg->{$propname}; }, $args); } $cur = &$out; foreach($props as $prop) { if(!isset($cur[$prop])) $cur[$prop] = array(); $cur = &$cur[$prop]; } $cur[] = $pg; } $event->return = $out; }); Edited February 25, 2024 by BitPoet Fixed more typos 14 1
rick Posted March 21, 2018 Posted March 21, 2018 How did you know I was needing this functionality just today. Great stuff! Thanks! 1
Robin S Posted March 22, 2018 Posted March 22, 2018 Thanks @BitPoet! I think there might be some typos in the mutator example - maybe you meant: $blogposts = $pages->find("template=blog-post, sort=created"); $grouped = $blogposts->groupBy(function($pg) { return array(strftime('%Y', $pg->created), strftime('%m', $pg->created)); }); 6
BitPoet Posted March 22, 2018 Author Posted March 22, 2018 54 minutes ago, Robin S said: I think there might be some typos in the mutator example Definitely. Thank for pointing that out, I have ammended my post. 4
gmclelland Posted January 3, 2024 Posted January 3, 2024 Thanks for sharing BitPoet! I did notice a couple of typos as well: * echo "<div class='year'><h2>$year</h3>" . PHP_EOL; and <div class='year'><h2>2016</h3> Notice the h2 and h3 don't match up?
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now