Use private function from one file in a public function in another

I have two files:

File get-calendar.php


namespace genesis\\calendar;

class Calendar {

	var $calendar;
	
	public function Get_calendar($date,$ministries,$limit) {
		global $mysqli;
		$query = 'SELECT calendar.event_name, calendar.calendar_id, calendar.ministry_id, calendar.start_date, venue.venue_name, ministry.ministry_name FROM calendar LEFT JOIN venue ON calendar.venue_id = venue.venue_id LEFT JOIN ministry ON calendar.ministry_id = ministry.ministry_id WHERE DATE(start_date) ' . $date . ' ';
		if ($ministries !== 'all') {
			$query .= 'AND calendar.ministry_id = "' . $ministries . '" ';
		}
		$query .= 'ORDER BY calendar.start_date ASC';
		if ($limit !== 'all') {
			$query .= ' LIMIT ' . $limit;
		}
		$result = $mysqli->query($query);
		if ($result) {
			while ($row = $result->fetch_array(MYSQLI_ASSOC)){
				$this->calendar[] = $row;
			}
			$result->close();
		} else {
			$this->calendar = NULL;
		}
		return $this->calendar;
	}
	
}

File set-calendar.php


use genesis\\calendar as C;
require_once($_SERVER['DOCUMENT_ROOT'] . "/genesis/data/class-get-calendar.php");

class Calendar {

	var $date;
	var $ministries;
	var $limit;
	var $calendar;
	var $num_results;
	
	function __construct($date,$ministries = 'all',$limit) {
		// Validate dates
		if (isset($_GET['from']) || isset($_GET['to'])) {
			if (isset($_GET['from'])) {
				if ($_GET['from'] == 'From') {
					$from = NULL;
				} else {
					$from = strtotime($_GET['from']);
					if (checkdate(date('m', $from),date('d', $from),date('Y', $from))) {
						$from = mysql_real_escape_string($_GET['from']);
					} else {
						$from = NULL;
					}
				}
			}
			if (isset($_GET['to'])) {
				if ($_GET['to'] == 'To') {
					$to = NULL;
				} else {
					$to = strtotime($_GET['to']);
					if (checkdate(date('m', $to),date('d', $to),date('Y', $to))) {
						$to = mysql_real_escape_string($_GET['to']);
					} else {
						$to = NULL;
					}
				}
			}
			if (!is_null($from) && !is_null($to)) {
				$this->date = 'BETWEEN "' . $from . '" AND "' . $to . '"';
			} else if (!is_null($from) && is_null($to)) {
				$this->date = '>= "' . $from . '"';
			} else if (is_null($from) && is_null($to)) {
				$this->date = '>= "' . date('Y-m-d') . '"';
			}
		} else {
			if (!is_numeric($date)) {
				$this->date = date('Y-m-d');
			} else {
				if (checkdate(date('m', $date),date('d', $date),date('Y', $date))) {
					$this->date = $date;
				} else {
					$this->date = date('Y-m-d');
				}
			}
			if (!is_null($this->date)) {
				$this->date = '>= "' . $this->date . '"';
			} else {
				$this->date = '>= "' . date('Y-m-d') . '"';
			}
		}
		// Validate ministry ID
		if (isset($_GET['ministry']) && is_numeric($_GET['ministry'])) {
			$this->ministries = mysql_real_escape_string($_GET['ministry']);
		} else if (is_int($ministries) || $ministries == 'all') {
			$this->ministries = $ministries;
		} else {
			$this->ministries = 'all';
		}
		// Validate limit
		if (is_int($limit)) {
			$this->limit = $limit;
		} else {
			$this->limit = 'all';
		}
	}
	
	public function Set_calendar($location) {
		$calendar = new C\\Calendar();
		$calendar = $calendar->Get_calendar($this->date,$this->ministries,$this->limit);
		if ($calendar == NULL) {
			$this->calendar = '';
		} else {
			if ($location == 'main') {		
				if (!empty($calendar)) {
					$this->calendar = '<table>
						<thead>
							<tr>
								<th>Event</th>
								<th>Date</th>
								<th>Time</th>
								<th>Venue</th>
								<th>Ministry</th>
							</tr>
						</thead>
						<tbody class="vcalendar">';
					foreach ($calendar as $key => $value) {
						$this->calendar .= '<tr class="vevent">';
						$this->calendar .= '<td><a class="url uid summary" href="/calendar/event.php?id=' . $calendar[$key]['calendar_id'] . '&amp;ministry=' . $calendar[$key]['ministry_id'] . '">' . $calendar[$key]['event_name'] . '</a></td>';
						$date = date('M. j, Y',strtotime(substr($calendar[$key]['start_date'],0,10)));
						$time = date('g:ia',strtotime(substr($calendar[$key]['start_date'],11,8)));
						$this->calendar .= '<td><span class="dtstart"><abbr class="value" title="' . date('Y-m-d',strtotime(substr($calendar[$key]['start_date'],0,10))) . 'T' . date('H:i:s',strtotime(substr($calendar[$key]['start_date'],11,8))) . '">' . $date . '</abbr></span></td>';
						$this->calendar .= '<td>' . $time . '</td>';
						$this->calendar .= '<td class="location">' . $calendar[$key]['venue_name'] . '</td>';
						$this->calendar .= '<td class="organiser">' . $calendar[$key]['ministry_name'] . '</td>';
						$this->calendar .= '</tr>';
					}
					$this->calendar .= '</tbody>
					</table>';
				} else {
					$this->calendar = '<h2>There are no events at this time</h2><p>Please check back often.</p>';
				}
			} else if ($location == 'sidebar') {
				$this->calendar = '<div id="calendar">';
				if (empty($calendar)) {
					$this->calendar .= '<p>There are no events at this time.</p>';
				} else {
					foreach ($calendar as $key => $value) {
						$this->calendar .= '<div class="calendar-event">';
						$number_date = substr($calendar[$key]['start_date'],8,2);
						if ($number_date < 10) {
							$number_date = substr($number_date,1,1);
						}
						$date = date('F j, Y',strtotime(substr($calendar[$key]['start_date'],0,10)));
						$time = date('g:i A',strtotime(substr($calendar[$key]['start_date'],11,8)));
						$this->calendar .= '<div class="calendar-event-numberdate">' . $number_date . '</div>';
						$this->calendar .= '<div class="calendar-event-title"><a href="/calendar/event.php?id=' . $calendar[$key]['calendar_id'] . '&amp;ministry=' . $calendar[$key]['ministry_id'] . '">' . $calendar[$key]['event_name'] . '</a></div>';
						$this->calendar .= '<div class="calendar-event-description">';
						$this->calendar .= '<div class="calendar-event-description-date">' . $date . '</div>';
						$this->calendar .= '<div class="calendar-event-description-time">' . $time . '</div>';
						$this->calendar .= '<div class="calendar-event-description-location">' . $calendar[$key]['venue_name'] . '</div>';
						$this->calendar .= '</div>
							</div>';
					}
					$this->calendar .= '<p class="small-links"><a href="/calendar/';
					if ($this->ministries !== 'all') {
						$this->calendar .= 'index.php?ministry=' . $calendar[$key]['ministry_id'];
					}
					$this->calendar .= '">View More ';
					if ($this->ministries !== 'all') {
						$this->calendar .= '<br />' . $calendar[$key]['ministry_name'] . ' ';
					}
					$this->calendar .= 'Events >></a></p>';
				}
				$this->calendar .= '</div>';
			}
		}
		return $this->calendar;
	}
	
}

I want to make the Get_calendar function in get-calendar.php private, but when I do, it throws me an error. I know it has to do with inheritance, but I am not sure ho to fix the problem.

I tried putting the require_once from set-calendar.php in the construct, but that didn’t work. I am guessing I have to extend Set_calendar in set-calendar.php, but I’m not quite sure the best way to do this.

Any advice would be much appreciated!

Once declared, the scope of a function cannot change. This is true of all languages which implement classical inheritance. Second, constructors have one and only one purpose - put the object in a ready state for execution. NEVER write a constructor that does anything else - it makes your code un-testable.

As written, Get_calendar cannot be private, otherwise Set_calendar in your second class won’t be able to access it.

To get you the right solution, we’ll have to address the bigger issue… why two calendar classes? What’s their relationship to each other supposed to be?

Maybe I am doing this wrong, please inform me if you think I am.

I am creating a CMS for a church. I would like to use the Calendar in the front end and the back end. I created the Calendar class in the first file, and placed it in one folder, and the Calendar class in the second file, and placed it in the other. I don’t want to have to write the first file’s Calendar class over and over, seeing that it’s use could be used in more than one way (front end to display the calendar, back end to edit a calendar, etc).

All of my database query files are in one folder, and all of my view files are in another. Then the front end references that view file to pull the different parts needed (calendar, mass schedule, events, etc).

Am I going about this the wrong way?

Here’s how I might do it. The code below is just a skeleton, but hopefully the structure is clear.

First, based on your get-calendar, it looks like a calendar is conceptually a list of events, so let’s make that first – just a generic calendar class.

class Calendar
{
	private $events;
	
	public function __construct($events)
	{
		$this->events = array();
		
		if (isset($events)) {
			$this->addEvents($events);
		}
	}
	
	public function addEvent($event)
	{
		$this->events[] = $event;
	}
	
	public function addEvents($events)
	{
		foreach ($events as $event) {
			$this->addEvent($event);
		}
	}
	
	public function getEvents()
	{
		return $this->events;
	}
}

Then, for translating between Calendar objects and database storage, we could make a calendar database class.

class CalendarDatabase
{
	public function findByDateRangeAndMinistry($dateFrom, $dateTo, $ministries, $limit)
	{
		$events = // sql select...
		// database escaping (i.e., mysql_real_escape_string) happens in here only
		
		return new Calendar($events);
	}
	
	public function save($calendar)
	{
		// sql insert, update....
	}
}

Next, your set-calendar looks like it handles the request, so we could make a calendar request class.

class CalendarRequest
{
	public function show()
	{
		$database = new CalendarDatabase();
		
		$calendar = $database->findByDateRangeAndMinistry($_GET['from'], $_GET['to'], $_GET['ministry']);
		
		return $this->render('calendar/show.php', array('calendar' => $calendar));
	}
	
	private function render($template, $params)
	{
		extract($params);
		
		ob_start();
		include $template;
		$content = ob_get_clean();
		
		return $content;
	}
}

And finally, the template.

// calendar/show.php
<?php if ($calendar): ?>
	<table>
		<?php foreach ($calendar->getEvents() as $event): ?>
			<tr>
				<td><?php echo htmlspecialchars($event['event_name']) ?></td>
				<td><?php echo htmlspecialchars($event['start_date']) ?></td>
				...
			</tr>
		<?php endforeach ?>
	</table>
<?php else: ?>
	There are no events at this time.
<?php endif ?>

We’ve broken the logic up into several files, and this allows each component to have a simple and focused responsibility. The Calendar class is responsible for a calendar’s behavior, and it doesn’t need to know or care about how it’s stored or presented. The CalendarDatabase class is responsible for mapping calendar objects to database tables and fields. The template is responsible for presenting a calendar, usually as HTML, but also possibly as JSON or an email message. And finally the CalendarRequest class is the glue. None of the other classes know about each other. CalendarRequest is the mediator that handles the interaction between the other components.

The term “MVC” is used a lot these days. In MVC nomenclature, the Calendar and CalendarDatabase classes would be the model, the CalendarRequest class would be the controller, and the template would be the view.

Thanks for putting so much time into showing me how you would do this. I really like what you’ve shown me, but I am still a little confused about how the extract function works with the template.

So I am guessing that the render function is what I call when I want to print the calendar events onto a page using:


$calendar = new CalendarRequest;
echo $calendar->render();

I understand that extract takes the key names from an array and places them in their own variable, but then when calling them, I am assuming in the example below you have the key names being “event_name” and “start_date”?

Is extract something that I should use? I feel like this doesn’t really allow you to visually see the array that you are calling, making the code cleaner, but a little harder to read if someone else was working on the project with me. To make it visually easier to read, if I decided not to use extract, I would just loop through the array?

Thanks again for all of your help with this. I really like how you laid it out much better than I had it. You also cleared up MVC for me, which I have been trying to understand and hadn’t quite grasped.

You would actually not call render yourself. In fact it’s private, so you can’t. You would call the show method.

$calendarRequest = new CalendarRequest();
$calendarHtml = $calendarRequest->show();

The show method uses the _GET params to ask the database for the appropriate calendar of events, then the show method itself calls render, passing in the calendar it just fetched.