I am just starting with Joomla component development and MVC in general. Im also not incredibly strong in PHP but I am trying to build a component that gets json and displays it as a jQuery accordion list.
I started by creating a PHP script that does just that and it works fine.
Now Im on the component part and the mvc is tripping me up. I adapted the hello world component in the docs tutorial found here: http://docs.joomla.org/Developing_a_Model-View-Controller_Component/3.1/Introduction
But when I install the component and go to my component I get:
Fatal error: Call to undefined function getProject() in /[path to joomla]/components/com_insightly/views/insightly/view.html.php on line 23 So my view cant use a function I defined in my model. I must be missing something because I thought the controller assigned the model to the view auto-magically.
Here is some source, (sorry im not indenting 8 spaces on each line manually)
site\models\insightly.php
// import Joomla modelitem library jimport('joomla.application.component.modelitem'); class InsightlyModelInsightly extends JModelItem { public function getProject($user_id) { $project_url = 'https://api.insight.ly/v2/projects/'.$user_id; $project = array(); $html_tag = null; $html_class = null; $html_id = null; $curl = curl_init($project_url); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Authorization: Basic NotGonnaShareThatNowAmI') ); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curl_response = curl_exec($curl); if ($curl_response){ $decoded = json_decode($curl_response, true); $i = 0; foreach ($decoded as $key=>$value){ // Eliminates Empty Fields and Saves to Multi-Dimensional Array if ($value){ $value = id_mask($value); } switch($key) { case "PROJECT_NAME": $key = null; $html_tag = "h1"; break; case "STATUS": $key = "Status"; $html_tag = "li"; break; case "PROJECT_DETAILS": $key = "Description"; $html_tag = "li"; break; case "RESPONSIBLE_USER_ID": $key = "Project Manager"; $html_tag = "li"; break; case "CATEGORY_ID": $key = "Category"; $html_tag = "li"; break; default: $value = null; } if ($value){ $field = [$key, $value, $html_tag, $html_class, $html_id]; $project[$i] = $field; $i++; } } return $project; } else { die('An error occurred retrieving Projects. Additional info: ' . curl_error($curl)); } curl_close($curl); } public function getActiveTasks($user_id){ $project_tasks = getTasks($user_id); $tasks = loopAndFind($project_tasks, 'STATUS', 'IN PROGRESS'); $i = 0; foreach ($tasks as $key=>$value){ $active_tasks[$i] = taskStyler($key, $value); $i++; } return $active_tasks; } public function getCompletedTasks($user_id){ $project_tasks = getTasks($user_id); $tasks = loopAndFind($project_tasks, 'STATUS', 'COMPLETED'); $i = 0; foreach ($tasks as $key=>$value){ $completed_tasks[$i] = taskStyler($key, $value); $i++; } return $completed_tasks; } function getTasks($user_id){ $task_url = 'https://api.insight.ly/v2/tasks'; $curl = curl_init($task_url); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Authorization: Basic NotGonnaShareThatNowAmI') ); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curl_response = curl_exec($curl); if ($curl_response){ $decoded = json_decode($curl_response, true); $project_tasks = loopAndFind($decoded, 'PROJECT_ID', $user_id); return $project_tasks; } else { die('An Error occurred retrieving Tasks. Additional info: ' . curl_error($curl)); } curl_close($curl); } //Search Tool for Multi-Dimensional Arrays function loopAndFind($array, $index, $search){ $returnArray = array(); foreach($array as $k=>$v){ if($v[$index] == $search){ $returnArray[] = $v; } } return $returnArray; } //Formats dates as d/m/Y and removes the time function date_formatter($value){ date_default_timezone_set('America/New_York'); $date = date_create($value); $value = date_format($date, "m/d/Y"); return $value; } //Returns array with ALLCAPS corrected and html tags function taskStyler ($key, $value){ $html_tag = "li"; $html_class = null; $html_id = null; switch ($key) { case "Title": $key = "Task"; $html_tag = "h3"; break; case "DUE_DATE": $key = "Due Date"; $value = date_formatter($value); break; case "COMPLETED_DATE_UTC": $key = "Date Completed"; $value = date_formatter($value); break; case "DETAILS": $key = "Details"; $value = strip_tags($value); break; case "STATUS": $key = "Status"; break; case "PERCENT_COMPLETE": $key = "Percent Complete"; $value = $value . "%"; break; case "START_DATE": $key = "Start Date"; $value = date_formatter($value); break; case "RESPONSIBLE_USER_ID": $key = "Assigned to"; $value = id_mask($value); break; default: $value = null; } if ($value){ $task = [$key, $value, $html_tag, $html_class, $html_id]; } else { $task = null; } return $task; } } site\views\insightly\view.html.php
// import Joomla view library jimport('joomla.application.component.view'); /** * HTML View class for the Insightly Component */ class InsightlyViewInsightly extends JViewLegacy { // Overwriting JView display method function display($tpl = null) { $user =& JFactory::getUser(); $user_id = $user->get( 'id' ); $user_id= "765727"; //Set for Development // Assign data to the view $this->project = getProject($user_id); $this->active_tasks = getActiveTasks($user_id); $this->completed_tasks = getCompletedTasks($user_id); parent::display($tpl); } } controller.php (which is empty)
// import Joomla controller library jimport('joomla.application.component.controller'); /** * Insightly Component Controller */ class InsightlyController extends JControllerLegacy { } site\insightly.php
<?php // No direct access to this file defined('_JEXEC') or die('Restricted access'); // import joomla controller library jimport('joomla.application.component.controller'); // Get an instance of the controller prefixed by Insightly $controller = JControllerLegacy::getInstance('Insightly'); // Perform the Request task $input = JFactory::getApplication()->input; $controller->execute($input->getCmd('task')); // Redirect if set by the controller $controller->redirect(); site\views\insightly\tmpl\default.php
<article id='project'> <?php $iterations = count($this->project); for ($i = 0; $i <= $iterations; $i++) { echo('<' . $this->project[2]); if (isset($this->project[3])) { echo('class ="' . $this->project[3]); } if (isset($this->project[4])) { echo('class ="' . $this->project[4]); } echo('>'); echo($this->project[0]); echo(' : '); echo($this->project[1]); echo('</' . $this->project[2] . '>'); } ?> <div id='tasks'> <h2>Active Tasks</h2> <section class='tasks'> <?php $number_of_tasks = count($this->active_tasks); for ($i = 0; $i <= $number_of_tasks; $i++) { $task_iterations = count($this->active_tasks[$i]); for ($i = 0; $i <= $task_iterations; $i++) { echo('<' . $this->active_tasks[$i][2]); if (isset($this->active_tasks[$i][3])) { echo('class ="' . $this->active_tasks[$i][3]); } if (isset($this->active_tasks[$i][4])) { echo('class ="' . $this->active_tasks[$i][4]); } echo('>'); echo($this->active_tasks[$i][0]); echo(' : '); echo($this->active_tasks[$i][1]); echo('</' . $this->active_tasks[$i][2] . '>'); } } ?> </section> <h2>Completed Tasks</h2> <section class='tasks'> <?php $number_of_tasks = count($this->completed_tasks); for ($i = 0; $i <= $number_of_tasks; $i++) { $task_iterations = count($this->completed_tasks[$i]); for ($i = 0; $i <= $task_iterations; $i++) { echo('<' . $this->completed_tasks[$i][2]); if (isset($this->completed_tasks[$i][3])) { echo('class ="' . $this->completed_tasks[$i][3]); } if (isset($this->completed_tasks[$i][4])) { echo('class ="' . $this->completed_tasks[$i][4]); } echo('>'); echo($this->completed_tasks[$i][0]); echo(' : '); echo($this->completed_tasks[$i][1]); echo('</' . $this->completed_tasks[$i][2] . '>'); } } ?> </section> </div> </article> <script src="http://code.jquery.com/jquery-1.10.2.js"></script> <script src="http://code.jquery.com/ui/1.10.4/jquery-ui.js"></script> <script> $(function () { $(".tasks").accordion({ collapsible: true, active: false }); }); </script> Any insight on why I cant get to my models function? Also I welcome the pointing out of any other blaring mistakes and security flaws.
EDIT: the idMask function was removed in my post due to sensitive content. It is probably not the issue.
EDIT: I have the component loading now and have updated the code but I'm having trouble with the arrays. taskStyler should return an array to be set to $completed_tasks[i].
completed_tasks[0][0] is correct but completed_tasks[0][1] contains an array composed of what should becompleted_tasks[0][1-12].
This is my current version of the relevant functions:
Calls getTasks and compiles array of tasks that are in progress
public function getActiveTasks($user_id){ $project_tasks = $this->getTasks($user_id); $tasks = $this->loopAndFind($project_tasks, 'STATUS', 'IN PROGRESS'); $i = 0; foreach ($tasks as $key=>$value){ $active_tasks[$i] = $this->taskStyler($key, $value); $i++; } return $active_tasks; } Calls getTasks and compiles array of tasks that are completed
public function getCompletedTasks($user_id){ $project_tasks = $this->getTasks($user_id); $tasks = $this->loopAndFind($project_tasks, 'STATUS', 'COMPLETED'); $i = 0; foreach ($tasks as $key=>$value){ $completed_tasks[$i] = $this->taskStyler($key, $value); $i++; } return $completed_tasks; } Curl session with API server that returns an array of tasks (known to work perfectly)
public function getTasks($user_id){ $task_url = 'https://api.insight.ly/v2/tasks'; $curl = curl_init($task_url); curl_setopt($curl, CURLOPT_HTTPHEADER, array( 'Content-Type: application/json', 'Authorization: Basic Dontlookatmypassword') ); curl_setopt($curl, CURLOPT_HEADER, 0); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); $curl_response = curl_exec($curl); if ($curl_response){ $decoded = json_decode($curl_response, true); $project_tasks = $this->loopAndFind($decoded, 'PROJECT_ID', $user_id); return $project_tasks; } else { die('An Error occurred retrieving Tasks. Additional info: ' . curl_error($curl)); } curl_close($curl); } Returns an array representing a datafield of a task with the keys and some values edited for readability, and html tags, classes and ids appended.
public function taskStyler ($key, $value){ $html_tag = "li"; $html_class = null; $html_id = null; switch ($key) { case "Title": $key = "Task"; $html_tag = "h3"; break; case "DUE_DATE": $key = "Due Date"; $value = $this->dateFormatter($value); break; case "COMPLETED_DATE_UTC": $key = "Date Completed"; $value = $this->dateFormatter($value); break; case "DETAILS": $key = "Details"; $value = strip_tags($value); break; case "STATUS": $key = "Status"; break; case "PERCENT_COMPLETE": $key = "Percent Complete"; $value = $value . "%"; break; case "START_DATE": $key = "Start Date"; $value = $this->dateFormatter($value); break; case "RESPONSIBLE_USER_ID": $key = "Assigned to"; $value = $this->idMask($value); break; default: $value = null; } if ($value) { $task = [$key, $value, $html_tag, $html_class, $html_id]; } else{ $task = null; } return $task; }