Jump to content
J_Szwarga

Custom Page Type...findOne() not implemented?

Recommended Posts

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?

Share this post


Link to post
Share on other sites

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 by gebeer
removed whitespace

Share this post


Link to post
Share on other sites
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()

  • Like 3

Share this post


Link to post
Share on other sites
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);
	}

 

  • Like 1

Share this post


Link to post
Share on other sites
Quote

And simply using $this->pages->findOne() inside Events can't do the job ?

Works great for me too, thanks!

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.

×
×
  • Create New...