Jump to content

Sub arrays, dates, times and pure hell


Joss
 Share

Recommended Posts

Okay, so, like I have said many times before, I ain't no coder!

I am currently taking an old and tired static angling site and turning it into a singing and dancing, Bootstrap 3, Mobile first, Processwire site - which seemed a good idea at the time!

The reason is that the bloke wot did the website is retiring and the "committee" will need to update it.

Now, the problem

I need to create a very basic events page that will be laid out more or less like the original

http://www.harlestonanglingclub.co.uk/Bookings.php

So, I create a small handful of fields and bung them in a repeater - they will never display many events in one go, so this does not need to be more complicated.

I have a event_start_date and an event_end_date field with the output format set at none - so it spits out the time format.

What I need to do is:

1. Split the resulting array up by month so that I have several new arrays, each one being a specific month in a specific year. (I have no idea what the months or years will be; this will be defined by what is in the array)

2. Loop through each of those resulting arrays to produce a table - probably using the "month" from the result displayed at the top of the table, then the rest of the results as shown.

However, I have not the slightest idea HOW to take my repeater field array and split it into new arrays by month and ... well you get the idea.

HELP!!!!

Loads of Love

Joss

Link to comment
Share on other sites

this is my ghetto way of doing it, but wrote this in browser so more to give some ideas, i think there are still some issues with doing it this way...

<?php 

	// get all of the events
	$events = $page->events;
	$years = array();
	
	// find the array of years for all events
	foreach ($events as $event) {
		$years[]= date("Y", $event->getUnformatted("event_start_date"));
		// change the format of the year in memory for later comparison
		$event->event_start_date = date("Y", $event->getUnformatted("event_start_date"));
	}

	$years = array_unique($years);
	asort($years);

	foreach($years as $key => $year) {

		// find the array of events this year
		$year_events = $events->find("event_start_date=$year");
		$months = array();

		// loop through the events for this year and add the months to the array
		foreach ($year_events as $year_event) {
			$months[]= date("m", $event->getUnformatted("event_start_date"));
			$event->event_start_date = date("m", $event->getUnformatted("event_start_date"));
		}

		$months = array_unique($months);
		asort($months);

		foreach($months as $key => $month) {
			$month_events = $events->find("event_start_date=$month");

				foreach($month_events as $e) {
					// output the table here
				} // end foreach events for this month

		} // end foreach months
	
	} // end foreach years
?>
Link to comment
Share on other sites

Okay, I output just the following (where you say to output the table) to see what is happening 

$out .="<p>{$e->event_start_time} - {$e->event_who}</p>"; (event_who is just a field with a name in it so I can see what is outputing)

But all I got was:

"12 Mickey"

I have no idea what the 12 is - the Mickey event is in February 2014.

What am I missing?

Thanks, Macrura

Joss

Link to comment
Share on other sites

hi joss -

sorry - i think one reason why this isn't going to work yet is because we reset the variable in memory for $event->event_start_date so it probably has to be unset after each of the foreach statements that obtain the arrays of years and months...

Link to comment
Share on other sites

If I understand correctly, you can also simply store these values on a new property instead:

foreach ($events as $event) {
    $years[]= date("Y", $event->getUnformatted("event_start_date"));
    // <del>change</del> format of the year in memory for later comparison
    $event->event_start_date_for_comparing_later = date("Y", $event->getUnformatted("event_start_date"));
}
 
Link to comment
Share on other sites

wow - thanks diogo i didn't know you could do that, i.e. set a new property for the page array...

so this would be an altered version based on that..

<?php 

	// get all of the events
	$events = $page->events;
	$years = array();
	
	// find the array of years for all events
	foreach ($events as $event) {
		$years[]= date("Y", $event->getUnformatted("event_start_date"));
		// change the format of the year in memory for later comparison
		$event->event_year = date("Y", $event->getUnformatted("event_start_date"));
	}

	$years = array_unique($years);
	asort($years);

	foreach($years as $key => $year) {

		// find the array of events this year
		$year_events = $events->find("event_year=$year");
		$months = array();

		// loop through the events for this year and add the months to the array
		foreach ($year_events as $year_event) {
			$months[]= date("m", $year_event->getUnformatted("event_start_date"));
			$event->event_month = date("m", $event->getUnformatted("event_start_date"));
		}
		$months = array_unique($months);
		asort($months);

		foreach($months as $key => $month) {
			$month_events = $events->find("event_month=$month");

				foreach($month_events as $e) {
					// output the table here
				} // end foreach events for this month

		} // end foreach months
	
	} // end foreach years
?>
  • Like 1
Link to comment
Share on other sites

Okay, nearly there!

Actually, now you have given unique variable names, it is much less confusing! I can almost get the workflow, despite my aged brain.

In the code below I am outputing the year as an H2, then the month as an H3 (just for convenience). 

The code is happilly listing the years and the associated months.

However, when it comes to outputting the actual event, it is only outputting the most recent event for the most recent month and not the others in the other months.

Note: This code is set up as a function and I have corrected the variable names since I accidentally gave the wrong ones in the original post - sorry!

Thanks guys, we are definitely getting there!

<?
function events() {
    // get all of the events
    $events = wire("page")->events; //gets the repeater field
    $years = array();
    
    $out ="";
    // find the array of years for all events
    foreach ($events as $event) {
        $years[]= date("Y", $event->getUnformatted("event_start_time"));
        // change the format of the year in memory for later comparison
        $event->event_year = date("Y", $event->getUnformatted("event_start_time"));
    }

    $years = array_unique($years);
    asort($years);

    foreach($years as $key => $year) {

        // Output the year
        $out .="<h2>{$year}</h2>";

        // find the array of events this year
        $year_events = $events->find("event_year=$year");
        $months = array();

        // loop through the events for this year and add the months to the array
        foreach ($year_events as $year_event) {
            $months[]= date("m", $year_event->getUnformatted("event_start_time"));
            $event->event_month = date("m", $event->getUnformatted("event_start_time"));
        }
        $months = array_unique($months);
        asort($months);

        foreach($months as $key => $month) {
            
            // Output the month as a number
            $out .="<h3>{$month}</h3>";

            // Set up a variable for the next loop of events
            $month_events = $events->find("event_month=$month");

                foreach($month_events as $e) {

                        $out .="<p>{$e->event_who}</p>";

                    // output the table here
                } // end foreach events for this month

        } // end foreach months
    
    } // end foreach years

echo $out;
}
 ?>
  • Like 1
Link to comment
Share on other sites

ryan did once tell me a long time ago that, if they have at least one event per month, it's actually less intensive to just generate all months and years from a given start date to today with just PHP and not iterating through every single event (the way it's being approached above doesn't scale infinitely basically, but would be fine for most sites).

What you could do is get the single event with teh date that's furthest in the future, then iterate through all the months and years between the current month and that event and create links for each month and year that way.

EDIT: Silly me, you want to print all the event details anyway so this is irrelevant in this case, but useful to bear in mind for someone who might just want to have a menu for months and years that click through to an events list (or blog or some such thing where you might want to have links to all past years etc with potentially thousands of pages behind them). But yeah, not relevant in this case at all!

  • Like 1
Link to comment
Share on other sites

Joss - maybe try echoing the count of month_events 

echo count($month_events);

and make sure it is the right # of events being returned by the selector  $events->find("event_month=$month");

also maybe echo all the other variables to make sure nothing is going wrong somewhere, check the debug also?

Link to comment
Share on other sites

Hi Macrura

I have been putting the count right at the end of the function.

Counting the $years variable is returning the right number - 2 (2013 and 2014)

Counting the $months variable is returning 1 - this is not right. I have three events in three different months, so it should be returning 3

However, if I put count($months) BEFORE the last foreach (the events one), it returns the right number - so something is breaking with that last foreach.

I have tried debug, but it is happy with everything, which doesn't surprise me as I cant see any code errors.

Joss

Link to comment
Share on other sites

Okay, just noticed another oddity. 

I put an event in november 2014. It is displaying that under november 2014 (good!)

However, although no other events are showing, the Nov 2014 event is also showing under Nov 2013 .... ummm!

It does not seem to be relating to the year.

Joss

Link to comment
Share on other sites

Okay, I think I have worked out the year confusion - I have changed the last find to

$month_events = $events->find("event_month=$month, event_year=$year");

However, that has not solved the original problem of only one actual event showing.

Link to comment
Share on other sites

Right, I think I have a vague idea about the problem.

This line:

        foreach ($year_events as $year_event) {
            $months[]= date("m", $year_event->getUnformatted("event_start_time"));
            $event->event_month = date("m", $event->getUnformatted("event_start_time"));
        }

If I add $Out .= $event->event_month to the loop it just returns 11, which is the month associated with the very last event. If I move that event to october, it returns 10.

Now, if I change the loop so that the last line is:

$event->event_month = date("m", $year_event->getUnformatted("event_start_time"));
 

Then my check outputs all the correct months.

However, I am still not getting my events. 

Closer, perhaps?

Link to comment
Share on other sites

hey Joss - maybe see if this is better... still untested:

<?
function events() {
    // get all of the events
    $events = wire("page")->events; //gets the repeater field
    $years = array();
    
    $out ="";
    // find the array of years for all events
    foreach ($events as $event) {
        $years[]= date("Y", $event->getUnformatted("event_start_time"));
        // add properties event_year and event_month to the $event object
        $event->event_year = date("Y", $event->getUnformatted("event_start_time"));
        $event->event_month = date("m", $event->getUnformatted("event_start_time"));
    }

    $years = array_unique($years);
    asort($years);

		// for testing
		// print_r($years);
		// print_r($events);

    foreach($years as $key => $year) {

        // Output the year
        $out .="<h2>{$year}</h2>";

        // find the array of events this year and put into new array $year_events
        $year_events = $events->find("event_year=$year");
        	// print_r($year_events);

        // loop through the events for this year and add the months to the array
        $months = array();
        foreach ($year_events as $year_event) {
            $months[]= date("m", $year_event->getUnformatted("event_start_time"));
        }
        $months = array_unique($months);
        asort($months);
        	// print_r($months);

        // loop through the months and find events for the month
        foreach($months as $key => $month) {
            
            // Output the month as a number
            $out .="<h3>{$month}</h3>";

            // filter only the events for this month, from the $year_events array.
            $month_events = $year_events->find("event_month=$month");
            	// print_r($month_events);

                foreach($month_events as $e) {
                        $out .="<p>{$e->event_who}</p>";
                } // end foreach events for this month

        } // end foreach months
    
    } // end foreach years

echo $out;
}
 ?>
*maybe joss or a moderator could mark this as best answer?
  • Like 2
Link to comment
Share on other sites

Well, it seems to be working fine now!

This sort of thing is REALLY REALLY useful!

Why don't you do it up as a little tutorial, explaining in more detail exactly how you are extracting data using processwire and how to use nested loops?

There are a lot of people like me on here that would appreciate it!

All the best

Joss

Link to comment
Share on other sites

yeah - should probably do that - cheers!

also - once you start setting up your markup for output, there are some things you can do to get the month names to output how you want (instead of numbers), usually done using php built in strtotime http://php.net/manual/en/function.strtotime.php , so you can pass the month as a string and then format it any way you want once you tell php that it's a date; http://www.php.net/manual/en/datetime.formats.date.php; since you are sorting by the month number, so those will appear in the right order;

the last project i did i needed to customize the output of the day names, so i used a switch statement in the loop, something similar for this, in case you don't want to use the php date:

<?php
				switch ($month) {
				case 01:
			        $monthName = "January";
			        break;
			        case 02:
			        $monthName = "February";
			        break;    
			    // etc..
				}
Link to comment
Share on other sites

The way I did that was to use the date() function, eg:

$start_date = date("l jS", $e->getUnformatted("event_start_time"));
$out .="<td><strong>{$start_date}</strong></td>";

to give me the day name and the day number (with a th or nd on the end)  - Saturday 19th

Link to comment
Share on other sites

yes - that would work for the events themselves; but before you start foreaching through the month's events, if you wanted to for example output headers for each month, you could also use the existing $month variable and then strtotime it to get your month name, or use the switch..

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