J_Szwarga Posted January 22, 2020 Share Posted January 22, 2020 I created a custom page type almost exactly as in the tutorial here: https://processwire.com/docs/tutorials/using-custom-page-types-in-processwire/ Everything working great with custom methods that I added to the Event object as well as the Events object. However, whenever I try to use $events->findOne($selector) I get Method Events::findOne does not exist or is not callable in this context $events->find() works, and $events->get() works. But I need findOne since I dont want to retrieve the page if it is not viewable. Since my $events class is based on PagesType, I thought that findOne should come with that for free. But looking at the PagesType class, there is no findOne method at all... I'm confused why PagesType doesn't implement findOne, and how do I get my custom events class to make that method available? Link to comment Share on other sites More sharing options...
gebeer Posted January 23, 2020 Share Posted January 23, 2020 (edited) The findOne() method is defined in Pages (wire/core/Pages.php). Since your custom Events class extends PagesType, there is no findOne() method available out of the box. You can add one, though. I did this and it worked for me. Here is my site/api/events.php Spoiler <?php namespace ProcessWire; // site/api/events.php class Events extends PagesType { /** * @var PagesLoader * */ protected $loader; /** * Construct the Events manager for the given parent and template * * @param Template|int|string|array $templates Template object or array of template objects, names or IDs * @param int|Page|array $parents Parent ID or array of parent IDs (may also be Page or array of Page objects) */ public function __construct($templates = array(), $parents = array()) { parent::__construct($this->wire(), $templates, $parents); // Make sure we always include the event template and /events/ parent page $this->addTemplates("event"); $this->addParents(2270); $this->setPageClass('Event'); $this->loader = $this->wire(new PagesLoader($this->wire('pages'))); } /** * Custom method to find by date range * * @param int $start timestamp * @param int $end timestamp * @param string|null $additionalSelector (optional) * @return PageArray */ public function findInDateRange($start, $end, $additionalSelector = null){ // Build selector $selector = "enddate>=$start, (enddate<=$end), (startdate<=$end)"; if($additionalSelector) $selector .= ", " . $additionalSelector; // Search only the available events with the selector return $this->find($selector); } /** * Like find() but returns only the first match as a Page object (not PageArray). * * This is functionally similar to the `get()` method except that its default behavior is to * filter for access control and hidden/unpublished/etc. states, in the same way that the * `find()` method does. You can add an `include=...` to your selector string to bypass. * This method also accepts an `$options` array, whereas `get()` does not. * * ~~~~~~ * // Find the newest page using the blog-post template * $blogPost = $pages->findOne("template=blog-post, sort=-created"); * ~~~~~~ * * #pw-group-retrieval * * @param string|array|Selectors $selector Selector string, array or Selectors object * @param array|string $options See $options for $pages->find() * @return Page|NullPage Returns a Page on success, or a NullPage (having id=0) on failure * @since 3.0.0 * @see Pages::get(), Pages::find(), Pages::findMany() * */ public function findOne($selector, $options = array()) { return $this->loader->findOne($selector, $options); } } I basically just copied it over from wire/core/Pages.php Since the findOne() method makes use of $this->loader, we need to make sure that the loader is available in our custom class Events. So I added the loader var at the beginning of the class definition and in the construct() method, I instantiated it. Just did this right now to see if it works. In my case I now get a result for $events->findOne("date_publish_start<=now"); Edited January 23, 2020 by gebeer removed whitespace Link to comment Share on other sites More sharing options...
flydev Posted January 23, 2020 Share Posted January 23, 2020 10 hours ago, gebeer said: The findOne() method is defined in Pages (wire/core/Pages.php). Since your custom Events class extends PagesType, there is no findOne() method available out of the box. You can add one, though. And simply using $this->pages->findOne() inside Events can't do the job ? As PagesType extends Wire, it should be available as $events->pages->findOne() 3 Link to comment Share on other sites More sharing options...
gebeer Posted January 23, 2020 Share Posted January 23, 2020 1 hour ago, flydev ?? said: And simply using $this->pages->findOne() inside Events can't do the job ? This does the job perfectly, indeed. Thanks a lot for that simple yet elegant solution. So all you need to add to site/api/events.php is public function findOne($selector, $options = array()) { return $this->pages->findOne($selector, $options); } 1 Link to comment Share on other sites More sharing options...
J_Szwarga Posted January 23, 2020 Author Share Posted January 23, 2020 Quote And simply using $this->pages->findOne() inside Events can't do the job ? Works great for me too, thanks! Link to comment Share on other sites More sharing options...
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