Jump to content

Selector filter for multiple dates


a-ok
 Share

Recommended Posts

Within a pages selector... I'm building a filtering system (using checkboxes) and thus this allows the user to select a date range (today, this week, this weekend, this month, next month) and have built the functionality and selectors for this... for example...

$now = strtotime("now");
$saturday = strtotime("saturday this week");
$sunday = strtotime("sunday this week");

events_detail_dates_upcoming_start_date<=$now
events_detail_dates_upcoming_start_date<=$sunday
events_detail_dates_upcoming_end_date>=$saturday, events_detail_dates_upcoming_start_date<=$sunday

I'm using this with a filter->() so for example the full query would be, for example...

$events = $pages->find("template=events-detail, events_detail_dates_final_date>=$today");
$events->filter("events_detail_dates_upcoming_start_date<=$now");

This all works fine and if I was to add tags to this too I would do add

$events->filter("events_detail_dates_upcoming_start_date<=$now, tags.name=art|film");

This also works fine... but as I am using checkboxes, a user can select both "today" and "next month" and ideally what it would return are events that are both today and next month... (almost like how tags work with the | separator) but for each checkbox ticked, for dates, it adds a comma separator (I've coded it to do this) so for example...

events_detail_dates_upcoming_start_date<=1517080159,events_detail_dates_next_month_start_date<=1519844959, events_detail_dates_next_month_end_date>=1517512159

Ignoring the field names (won't bother explaining this) but is there a way to return events that have ALL those attributes... and not using commas to filter it down?

Link to comment
Share on other sites

I'm not sure I follow 100% so, I could be way off. I'm unsure which of the following 'understandings' apply :).

1 hour ago, oma said:

but is there a way to return events that have ALL those attributes... and not using commas to filter it down?

 

My understanding #1: You don't want to use Commas

Commas, Pipes, Equals signs, etc. all have their specific uses in ProcessWire's selector engine. Commas represent AND operator and Pipes OR operator. So, if you need ALL conditions to match, you have no choice but to use the AND operator, i.e. the Comma. 

I'm curious, why don't you want the commas?

 

My understanding #2: You don't want to use a Filter (aka, want one selector)

Do you mean a way to find only the matching events in one find rather than filtering them down using filter() [I'm probably way, way off here, since you are building a filtering system ???]

Link to comment
Share on other sites

@oma: Like @kongondo, I'm not completely sure if I'm getting your question right. Are you, perchance, looking for or groups, i.e. a way to tell the filter "return all events that fulfill the other criteria and are either today or next month"? In that case, you need to still use commas but surround the individual selector parts that are sufficient for a successful match with parenthesis.

$events = $pages->find(
	// Basic selector for all events not yet ended
	"template=events-detail, events_detail_dates_final_date>=$today"
	// First OR-group, today's events
	. ", (events_detail_dates_upcoming_start_date<=$now)"
	// Second OR-group, events next month
	. ", (events_detail_dates_next_month_start_date<=1519844959, events_detail_dates_next_month_end_date>=1517512159)"
);

This would get all events-detail pages not yet ended and - sticking to your example and using parenthesis to outline PW's syntax - either (running through today) or (running next month).

  • Like 1
Link to comment
Share on other sites

Thanks for your reply, guys. Sorry if I haven’t managed to explain things correctly.

@BitPoet‘s reply is definitely what I’m after HOWEVER I don’t think you can use the OR group parenthesis in a ->filter() but do correct me if I’m wrong?

I’m doing some checks before this code which requires me to use ->filter().

Link to comment
Share on other sites

Thanks guys. @Robin S yes that sounds like it should work... ->add(selector) is effectively filter->() but without it being destructive, right? So gives me full access.

This is essentially but code so far so reckon I could totally use ->add() on this. Much appreciated help!

        $dateFormat = date('D. j F Y');
        $today = strtotime($dateFormat);
        $first_day_of_next_month = strtotime("first day of next month");
        $last_day_of_next_month = strtotime("last day of next month");

        $events = $pages->find("template=events-detail, events_detail_dates_final_date>=$today");

        foreach($events as $event) {

            // Get the repeater page with the next upcoming date
            $next_upcoming_date = $event->events_detail_dates->get("events_detail_dates_end_date>=$today, sort=events_detail_dates_end_date");

            //
            $next_month_start_date = 0; $next_month_end_date = 0;
            $next_month_start_date = $event->events_detail_dates->get("events_detail_dates_start_date<=$last_day_of_next_month, sort=-events_detail_dates_start_date");
            $next_month_end_date = $event->events_detail_dates->get("events_detail_dates_end_date>=$first_day_of_next_month, sort=-events_detail_dates_end_date");

            // Add the timestamp of the next upcoming date to the result as a custom property
            $event->events_detail_dates_upcoming_start_date = $next_upcoming_date->getUnformatted('events_detail_dates_start_date');
            $event->events_detail_dates_upcoming_end_date = $next_upcoming_date->getUnformatted('events_detail_dates_end_date');

            if (!empty($next_month_start_date) && !empty($next_month_end_date)) {
                $event->events_detail_dates_next_month_start_date = $next_month_start_date->getUnformatted('events_detail_dates_start_date');
                $event->events_detail_dates_next_month_end_date = $next_month_end_date->getUnformatted('events_detail_dates_end_date');
            }

        }

        $events->sort('events_detail_dates_upcoming_end_date');

        $calendar = $this->input->post->calendar;
        $query = $this->input->post->query;

        $events->filter("{$query}, {$calendar}");

 

Just now, BitPoet said:

And append


->unique() 

to remove duplicates.

Whoa that's good!

Link to comment
Share on other sites

If anybody wants to give it a try, here's a little attempt at an OR-group capable PageArray extension (just to see if this might be worth investing some more time and creating a PR).

Usage:

$regularPageArray = $pages->find("template=mytemplate");
// Returns an OrGroupsPageArray instance with the contents of $regularPageArray:
$groupable = $regularPageArray->getGroupable();

$groupable->filter("fieldA=1, (fieldB=today), (fieldB=tomorrow)");
// or
$filtered = $groupable->find("fieldA=1, (fieldB=today), (fieldB=tomorrow)");

 

OrGroupsPageArray.zip

  • Like 6
Link to comment
Share on other sites

11 hours ago, Robin S said:

You could filter the PageArray more than once and add the results together. Actually, filter() is destructive so use find() instead.


$results = $pagearray->find($selector_1)->add($pagearray->find($selector_2));

 

Thanks for this again, Robin. After looking at this I'm unsure if this is working...

$events = $pages->find("template=events-detail, events_detail_dates_final_date>=$today");

$calendar = $this->input->post->calendar;
$query = $this->input->post->query;

$results = $events->add($events->find("{$query}, {$calendar}"));

In this above example the $query could be the following (if upcoming start date is equal to or less than today)

events_detail_dates_upcoming_start_date<=1517171596

What result this is returning is the 'filtered' pages to the bottom off the original $events query... this is why the filter() option was good because it was removing any items that didn't match it the filter... not adding it to the original query. Any thoughts?

Link to comment
Share on other sites

31 minutes ago, oma said:

Thanks for this again, Robin. After looking at this I'm unsure if this is working...


$events = $pages->find("template=events-detail, events_detail_dates_final_date>=$today");

$calendar = $this->input->post->calendar;
$query = $this->input->post->query;

$results = $events->add($events->find("{$query}, {$calendar}"));

In this above example the $query could be the following (if upcoming start date is equal to or less than today)

In this example you only have a single query for modifying the original PageArray. So you don't need add() here - that is only needed for cases like your earlier example where you have multiple queries to apply to your PageArray where you want to say "find this" OR "find this".

// Your original PageArray (which you will reduce down from)
$pagearray = $pages->find($selector_1);

// First modifying query
$results = $pagearray->find($selector_2);
// Stop here if you only have a single modifying query

// Otherwise if you have additional OR queries, add them to the results
$results->add($pagearray->find($selector_3))

 

Link to comment
Share on other sites

Thanks, Robin. That makes sense!

Now the issue I seem to be experiencing is (when only have a single modifying query) is using an OR query...

For example...

$events = $pages->find("template=events-detail, events_detail_dates_final_date>=today");
$results = $events->find("(events_detail_dates_upcoming_start_date<=today)");
OR
$results = $events->find("(events_detail_dates_upcoming_start_date<=1517174937,events_detail_dates_upcoming_start_date<=1517097600)");

Seems to remove all the items (itemsRemoved when using Tracey Debugger). If I remove the parenthesis from the top modifier, for example, it works fine but obviously the parenthesis is required for the OR group. Any further thoughts?

Link to comment
Share on other sites

12 minutes ago, oma said:

it works fine but obviously the parenthesis is required for the OR group

I don't think OR groups are supported at all in WireArray (therefore PageArray) methods - adding support for OR groups inside a single PageArray selector is what BitPoet's module above is all about.

But if you are doing what I suggested with find() and add() then you don't need the OR group parentheses. It's a different approach but should result in the same thing as OR groups inside a single selector.

Link to comment
Share on other sites

10 minutes ago, Robin S said:

I don't think OR groups are supported at all in WireArray (therefore PageArray) methods - adding support for OR groups inside a single PageArray selector is what BitPoet's module above is all about.

But if you are doing what I suggested with find() and add() then you don't need the OR group parentheses. It's a different approach but should result in the same thing as OR groups inside a single selector.

Thanks again, Robin.

I thought, based on this page, https://processwire.com/api/selectors/#or-groups, that I was just using the OR groups inside a find() Page/WireArray? Or am I getting confused? Why would it work when doing one find() and not find()->find() for example?

Link to comment
Share on other sites

44 minutes ago, oma said:

I thought, based on this page, https://processwire.com/api/selectors/#or-groups, that I was just using the OR groups inside a find() Page/WireArray? Or am I getting confused? Why would it work when doing one find() and not find()->find() for example?

The documentation could be clearer in this regard, and I'm probably oversimplifying here, but there two basic categories of selector usage in PW.

1. Methods that use the PageFinder class - common ones would be $pages->find($selector), $pages->get($selector), $page->children($selector). Also find/get selectors for $users. Those are the ones that spring to mind, although there might be a few more. These methods do a database query behind the scenes.

2. All other methods that accept a selector, for example $some_pagearray->find(), which is actually WireArray::find(). These methods do not query the database but work on items that are in memory.

There are differences in the ways that these two categories of selector usage are implemented. Some things work in a PageFinder selector that don't work in an in-memory selector. The documentation for Selectors seems to be assuming the reader is interested in PageFinder selectors because there are code examples there that won't work with in-memory selectors. There isn't any definitive list of the differences (that I know of), but here are some things that I have found do not work with in-memory selectors (but do work with PageFinder selectors):

1. Datetime values as strings, e.g. "some_datetime_field>today"

2. Page statuses as strings, e.g. "status!=hidden"

3. OR groups

In a perfect world selectors would work the same everywhere and you wouldn't have to think about it. There's an open request for this here.

  • Like 7
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...