Jump to content

Get specific page attributes/fields from pagearray set


Bill
 Share

Recommended Posts

I have a pageArray "$p" - that contains 10 pages; how can i get any particular attribute from each one without formally setting up a foreach/iteration over the 'set'.

something like

$p = $pageArray->getField('id');

... where it would return all the id's of all child pages / pages within the pageArray?

I'm sure this already exists. thanks!

Edited by Bill
Link to comment
Share on other sites

I don't think you could do it without iteration, but if you're trying to get a subset, you could possibly do something like this (though I've not tested it):

// Let's assume $p is your 10 pages in a page array as you say, and $myfield is the field you're trying to filter on
$subset = $p->find("$myfield!=");

I seem to recall that that will return all pages where $myfield is not empty (as in it's not equal to "nothing" ;)).

$subset therefore now contains your filtered list. Let me know if that works.

My query would be why you would want to get a subset without iterating through them? Surely you have to iterate through them at some point to output some content?

Link to comment
Share on other sites

Whyno for each? That what.it for. Already invented wheel is.

$ids=array();
foreach($pageArray as $p) $ids[]=$p->id;

Now bingo $ids have.what u need

Thanks!

Yeah, i don't mind doing it but i was hoping that there was a method like....

$pageArray->children()->getAttr('id');
Link to comment
Share on other sites

I don't think you could do it without iteration, but if you're trying to get a subset, you could possibly do something like this (though I've not tested it):

// Let's assume $p is your 10 pages in a page array as you say, and $myfield is the field you're trying to filter on
$subset = $p->find("$myfield!=");

I seem to recall that that will return all pages where $myfield is not empty (as in it's not equal to "nothing" ;)).

$subset therefore now contains your filtered list. Let me know if that works.

My query would be why you would want to get a subset without iterating through them? Surely you have to iterate through them at some point to output some content?

Gotcha - yep aware of the find method, and thanks for explaining more thoroughly for this application of it.

I am mainly interested in if there's a pre-established method i might be missing is all... like "->children('')->getAttr('id')" or something of that nature... that would 'internally' to the Wire/PageArray class would iterate thru the pages to get an array/object of all the id's for that particular pageArray set, like ... 3, 14, 23, 154, 161 -> allowing me to use them in a successive query based on those.

In particular i'm wanting to do a ->getRandom() of all the pages, but in my pagination results (of those pages) below, i don't want the random one to be of the same as those listed in the page[d] results below.

So, if the paginated listing below (showing page 2 of 10, the page id's are: 3, 14, 23, 154, 161 - then the random id i want to be still random but just including them).

I know i can DO it, i was just wanting to Quickly (one-liner) Methodize it is all :), like

$pagedIDs = $pageArray->children()->getAttr('id');

(pseudo-hack code :P)

Link to comment
Share on other sites

Well all you need to do is use something like what I posted and then keep chaining on successive filters if you then want to narrow it down more.

I've got to say though that out of any context it is very confusing to work out what you are trying to achieve. I've read it a few times now and I'm still scratching my head ;)

I honestly don't understand what you mean by this: ->children('')->getAttr('id')

Are you saying in that case that you want to get the ID's of all the children of the current set of pages (which is 10 pages in your example)? In which case you could be returning a rather large number of ID's if each page can have multiple children.

I think in this case you would have to use a foreach anyway if all you want is the 10 pages' child IDs - something like this:

// $p is your pagearray with 10 pages again
$childIDs = array();
foreach ($p->children as $child) {
$childIDs[] = $child->id;
}

If that's what you were trying to do, you won't find a method for it I don't think, mainly because I can't see a reason why you'd want to reinvent what PHP already does so well with just a couple of lines of code. Of course I may be wrong here and ryan may have built something in like this but after some testing I couldn't find one.

Link to comment
Share on other sites

// $p is your pagearray with 10 pages again
$childIDs = array();
foreach ($p->children as $child) {
$childIDs[] = $child->id;
}

Right, i can use the above, and i init. had that in there (my code) in the template itself, and was looking to remove 3 lines from it and just do (what you assumed already from my pseudo-hack-code above) which was

"get all the id's of the children associated with the pageArray object"

So,...

My next thought cuz i'd like to potentially do this for a multitude of uses, and to keep my code as DRY as possible... would you all recommend, when creating helpers (i know, i know... the CI in me coming thru - lol) like this (the foreach -> method by extending the PagesArray / WireArray class) that it's better to just simply create a catch-all 'helper' module? or do a general include int he head.inc (for ex.)?

Link to comment
Share on other sites

I did end up having a lot of code that I needed to run to check various things on a site I'm currently building so I just went with the include file in head.inc like you say. Keeps things very neat and tidy in the template and is the easiest way of doing it.

  • Like 1
Link to comment
Share on other sites

I did end up having a lot of code that I needed to run to check various things on a site I'm currently building so I just went with the include file in head.inc like you say. Keeps things very neat and tidy in the template and is the easiest way of doing it.

Interest'd in others' thoughts as well, but appreciate your K.I.S.S. approach and promptness (+1 @Pete! :))

Truly! Thx.

Link to comment
Share on other sites

Just fyi - here's what i'm doing...

(please save the 'stoning' for after i leave this forum... and get a head start on din-din with the family so i can proceed into heaven with a full stomache :P)

abstract class PageArrayHelper
{
 static function getAttr(PageArray $PageArray, $key='id')
 {
  $pageKeys = array();
  foreach ($PageArray as $page)
  {
   $pageKeys[] = $page->$key; // all pages have one! 
  }
  return $pageKeys;
 }
}

Then by just calling it as such...

$IDs = PageArrayHelper::getAttr($randomChildren);
// returns (array) of ids 

now i can include that in the header, and i'll use throughout... my thoughts on this were if i'm displaying content and/or random content elsewhere on the page, and/or footer type - 'also check this out -' i don't want to have that same content be placed all over the place, i want it to be in one spot and one spot only but the pagination would be more of the uber spot, with the other random spots being secondary... (right now only 1 random spot, but you get the idea).

Link to comment
Share on other sites

Bill, if I look at your code I just keep thinking that I would do this. And look! Without foreach!

$rand_children = $pages->find("template=basic-page")->getRandom(3);
echo $rand_children; // returns 102|230|323
$ids = explode("|",$rand_children);
print_r($ids); // array with id's

..so a one liner would be this:

$ids = explode("|", $pages->find("template=basic-page")->getRandom(3));
Link to comment
Share on other sites

Bill, if I look at your code I just keep thinking that I would do this. And look! Without foreach!

$rand_children = $pages->find("template=basic-page")->getRandom(3);
echo $rand_children; // returns 102|230|323
$ids = explode("|",$rand_children);
print_r($ids); // array with id's

..so a one liner would be this:

$ids = explode("|", $pages->find("template=basic-page")->getRandom(3));

Right - thanks Soma - i'm honored with your reply, you're an active person in these forums, and in developing kick-butt modules/snippets :)...

My whole idea of grabbing the random would be to grab a random value was to on each page shown to the browser/user, that i have a paginated result set... (ie, showing page 2 of 10), then i want to show a random one (ie, at the top, at the bottom, or in the sidebar area) but I don't want the random one to be the same as any of those shown on that particular page #2 list.

So, my idea was to grab the paginated list - that's the main priority, and then from that list grab their ID's and then grab a random page from this template, where NOT IN in the list of ID's shown.

I'll play with the find() feature a bit more, and see how i can incorporate that into my page -

... will follow-up shortly.

[followup]

not sure what i'm doing wrong, but whenever i do a lookup using find("template={template_name}") or even a $page->children("template={template_name}") the system just goes into this churning fit to leave me with a blank freakin' page (lol).

still at it... i have a work around using my solution above, incorporating a find(!=) syntax, but was wanting to fully use what you're telling me to see which one is more effic. and as close to native PW as possible.

... i'm on it :)

Link to comment
Share on other sites

I think you can use array_diff() to compare $pages->find("template=basic-page") with $pages->find("template=basic-page, limit=10") and return the difference.

I didn't test it, and can't do it now.

Link to comment
Share on other sites

I think you can use array_diff() to compare $pages->find("template=basic-page") with $pages->find("template=basic-page, limit=10") and return the difference.

I didn't test it, and can't do it now.

okay but that'll probably do an internal foreach as well... negating the impact, but certainly one-line it ;).

also, as i mentioned in my updated post above, i'm getting WIERD 'churning without any results, blank screen' activity on my use of ->find(), or ->children() - when using the selector of "template=cool-page" (which is the page template i'm using for this particular page).

very wild...

also -

as an update to my code above...

here's the most succinct way i've found thus far to accomplish things (yes, using the helper class above, and i'm still open to getting ideas more closely knit to PW.... but here goes:

$children = $page->children('limit=3');
$ids = PageArrayHelper::getAttr($children,'id');
$randomChildNotInChildren = $page->children()->find("id!=".implode("|",$ids))->getRandom();

... let the stone throwin' begin! ;)

Link to comment
Share on other sites

i'm getting WIERD 'churning without any results, blank screen' activity on my use of ->find(), or ->children() - when using the selector of "template=cool-page" (which is the page template i'm using for this particular page).

This is not what it's supposed to do. This is probably the most common selector usage there is. Need some more information to determine what's going on here. Try turning on debug mode (/site/config.php) and edit the $config->debug line to be true. That should at least give a better sense of what error is getting thrown. Though if not, tell me more about this case. How many pages are there using 'template=cool-page' and how many 'autojoin' fields are part of it? If you are dealing with hundreds of pages you may want to place a limit=n on it.

Just fyi - here's what i'm doing...

This looks like a good approach. If you want to add your getAttr() method directly to the PageArray, so that you can call it like this:

$IDs = $randomChildren->getAttr('id'); 

...you can do it with an autoload module:

class YourModule implements Module {

static public function getModuleInfo() { 
  return array(
      'title' => 'Your Module',
      'version' => 100, 
      'summary' => 'Adds a getAttr() method to all PageArrays',
      'singular' => true,
      'autoload' => true
      ); 
}

public function init() {
   $this->addHook('PageArray::getAttr', $this, 'getAttr'); 
}

public function getAttr(HookEvent $event) {
   $pageArray = $event->object;
   $key = $event->arguments[0];
   // ...the rest of your code goes here...
   $event->return = $pageKeys; 
}

}
Link to comment
Share on other sites

I can't seem to edit my last message without having it convert everything to entities (something not working right with the forum). I just wanted to mention the class line should be this instead:

class YourModule extends Wire implements Module {
Link to comment
Share on other sites

This is not what it's supposed to do. This is probably the most common selector usage there is. Need some more information to determine what's going on here. Try turning on debug mode (/site/config.php) and edit the $config->debug line to be true. That should at least give a better sense of what error is getting thrown. Though if not, tell me more about this case. How many pages are there using 'template=cool-page' and how many 'autojoin' fields are part of it? If you are dealing with hundreds of pages you may want to place a limit=n on it.

Right this is with the debug already set to TRUE. It's like it churns, churns, etc... on my localhost and then stalls out... nothing, no unseen html either... the page source is blank. Only (i mean ONLY) when i do the find('template=cool-page') syntax. As you can see from above, the find('id!=...') works like a champ - and fast as heck!

This looks like a good approach. If you want to add your getAttr() method directly to the PageArray, so that you can call it like this:

$IDs = $randomChildren->getAttr('id'); 

...you can do it with an autoload module:

// editted already as per your update above
class YourModule extends Wire implements Module {

static public function getModuleInfo() {
  return array(
   'title' => 'Your Module',
   'version' => 100,
   'summary' => 'Adds a getAttr() method to all PageArrays',
   'singular' => true,
   'autoload' => true
   );
}

public function init() {
$this->addHook('PageArray::getAttr', $this, 'getAttr');
}

public function getAttr(HookEvent $event) {
$pageArray = $event->object;
$key = $event->arguments[0];
// ...the rest of your code goes here...
$event->return = $pageKeys;
}

}

By autoload, you're stating that this would be a module that i could put inside my site's modules' folder and install it and it then autoloads it?

Thanks,... i'm still a bit unclear as to how to make my own module... i'm assuming that what you've done above it does essentailly that.

I'd put it there, inside my site/modules folder, as such, check for new modules, install that module, and it'll autoload. And, upon teh use of the 'PageArray' instance, i'll now have the 'hook' for getAttr, which will be a part of the extension of Wire - as does PageArray.

Right?

(sorry, feelin' n00b to this PW stuff still, but testing a ton of things out for my next project... it's all swirling in my head right now...) ;)

THANKS for taking the time to do this above tho.

[EDIT]

Just curious, why is it an abstract call to that method, and not directly... conversely, if i used it to only extend the PageArray and implement Module, then wouldn't it be a direct call?

(sorry, my lack of uber-PHP genius is showing... )

Link to comment
Share on other sites

just a follow up for clarity's sake only -

I implemented (no pun intended) the above module, created my module as such, invoked the $page->children()->getAttr('id') request and voila, the EXACT same id's that i expect! Only now, instead of foreach's, extra php within the template/header, i have my *very own* (blush! tear runs down the cheek) module ;) that i can now tweak and incorporate new goodness within..., now gets invoked when i call.

This rawks! to no limited level, Ryan. Thanks.

Link to comment
Share on other sites

continuing on this ePic journey...

how would i grab the $input->urlSegment1 stuff/lingo from within the module itself..

i init. did the lazy way of 'global $input' but got nuttin' :)

In a module it's not the same as in template level, in a module you use

wire("input")->urlSegment1;
$wire->input->urlSegment1;

or $this

$this->input->urlSegment1;
Link to comment
Share on other sites

In a module it's not the same as in template level, in a module you use

wire("input")->urlSegment1;
$wire->input->urlSegment1;

So (as in the above), you're accessing the (object) "input" via the PW API, right?

And, in the code below, you're accessing it via the Wire (that this module is actually extending)

or $this

$this->input->urlSegment1;

And, since it's extending the Wire, obviously $this->input is all that's needed. (gotcha!)

Now, just for my information, is using one over the other preferred?

I'm assuming $this->input->....

Reason I'm asking is that if i use the wire() API in the future from outside of PW (typ. Wire API usage), will it totally "reflect" on my module better if it's incorporated using the wire("input") vs. the $this->input???

Just don't want to back myself into a corner is all :).

Link to comment
Share on other sites

@Soma - thanks for the tip, and guidance :)

@Ryan - what the 'oh my!' brain cell implant did you have to come up with such a ridiculously versatile system, Ryan. I mean really! I created plugins for WP, addons for a few others, and 'implementing' your modules (once i've now done it) is like a cakewalk... no FUNKY nomenclature, tricks, 'jam this into here...' and the ever-present 'oh yeah, you can't do that here so you have to hack your way in this way' stuff... period.

Just soup to nuts, awesome, using observer patterns, full reflection, and keeping everyone on the handrail using "implements" in modules you rawk Ryan! (... and obviously the community that supports ya! :P)

Thanks all again...

Maybe i'll post my two new modules... for anyone else who wants to use them. Just launch platforms is all - for making new/improved modules and sorts.

Edited by Bill
  • Like 1
Link to comment
Share on other sites

Thanks Bill, I think the main difference is just PHP5. There is a lot about PHP5 that really benefits the ability to build simpler plugin systems. WP and others are still built around a PHP4 idea of plugins, probably for legacy support reasons.

Reason I'm asking is that if i use the wire() API in the future from outside of PW (typ. Wire API usage), will it totally "reflect" on my module better if it's incorporated using the wire("input") vs. the $this->input???

It doesn't really matter much which you use. But here are a couple factors. I definitely like the readability of $this->apiVar better, but the truth is that using wire('apiVar') is more bulletproof. In order to use $this->apiVar, you have to be in a class that extends Wire, and you can't take control over the __get() method in the class. Or at least if you do, you have to make yours call parent::__get() when your class doesn't have a handler for a given variable. So if you are using wire() exclusively, you really don't have to worry about things when you override a __get() method. Also, wire() doesn't have to pass through any comparisons, as it's singular purpose, so technically a little more efficient. Lastly, wire() can be used in procedural functions, and in classes that don't extend Wire, making it portable for use anywhere in your site's code. Still, it may not feel right to rely on a procedural function to access API vars. But if you can get past that feeling, it actually makes a lot of sense to use it. It's kind of like PW's version of jQuery() or $(). Using wire() is newer syntax, and not something you could do in the original PW 2.0. So I haven't standardized on one or the other, and use both interchangeably, and PW will always support both. Also want to note that PW passes all the API vars to your template files, so you don't have to use wire() or $this, and instead you can just access them directly, like $pages.

Link to comment
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
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...