Simplifying CodeIgniter controllers - codeigniter

I have a block of code I'd like to put in my CI 2.x core folder and reuse via a base controller that would be extended by all of my other controllers.
Here is the code that appears in every controller and I want to move to somewhere more central:
$data['navigation'] = generate_navigation(); // helper function
$data['country'] = code2country(); // helper function
$data['langs'] = $this->select_country_model->get_langs();
// Get copy and images for page
$query = $this->common_model->get_content('markets', 'architectural');
// Load title, description and keywords tags with data
foreach ($query as $row) {
$data['title'] = $row->page_title;
$data['description'] = $row->description;
$data['keywords'] = $row->keywords;
}
How do I put this in my base controller (MY_controller.php) and then send the data to my view from the extended controller. Do I still use $data[] = and $this->load->view('whatever', $data)?

Yeah, you can still pass this along in a $data variable, but you'll need to assign it so that you can access it from the other controller like this:
class MY_Controller extends CI_Controller {
var $data = array();
function __construct()
{
$this->load->model('select_country_model');
$this->load->model('common_model');
$this->data['navigation'] = generate_navigation(); // helper function
$this->data['country'] = code2country(); // helper function
$this->data['langs'] = $this->select_country_model->get_langs();
$query = $this->common_model->get_content('markets', 'architectural');
foreach ($query as $row) {
$this->data['title'] = $row->page_title;
$this->data['description'] = $row->description;
$this->data['keywords'] = $row->keywords;
}
}
}
Then just extend you controller with MY_Controller and you will have access to the $data with $this->data.

Related

Laravel pass value from foreach loop in controller to view

I am trying to get the data from a foreach loop in my controller to pass to my view. How do I do it?
Controller
class FormteachersController extends Controller
{
public function form_teachers_view(){
$UniqueStudent = Student::where('Student_ClassID','JSS 1C')->get();
foreach ($UniqueStudent as $keydata) {
$student = $keydata->Stud_id;
$result= Result::where('Term_ID','1st Term')->where('Student_ID',$student)->where('Class_ID','JSS 1C')->where('Session_ID','2225/2222')->get();
foreach ($result as $keyresult) {
echo '<br>'.'<br>'.$student.'-'.$result;
}
return view('teachers.form_teachers_comment_sec');
}
}
}
This is the output.
You can do something like this:
class FormteachersController extends Controller
{
public function form_teachers_view(){
$uniqueStudent = Student::where('Student_ClassID','JSS 1C')->get();
$uniqueStudentsData = [] ;
foreach ($uniqueStudent as $keydata) {
$student = $keydata->Stud_id;
$result = Result::where('Term_ID','1st Term')->where('Student_ID',$student)->where('Class_ID','JSS 1C')->where('Session_ID','2225/2222')->get();
foreach ($result as $keyresult) {
$uniqueStudentsData[] = '<br>'.'<br>'. $student.'-'. $keyresult;
}
}
return view('teachers.form_teachers_comment_sec', compact('uniqueStudentsData'));
// or pass array
return view('teachers.form_teachers_comment_sec',[
'uniqueStudentsData' => $uniqueStudentsData,
]);
}
}
Now, in your form_teachers_comment_sec.blade.php, run your foreach loop and do what do you want to there
// $uniqueStudentsData
#foreach($uniqueStudentsData as $data)
// do what do you want
#endforeach
Hopefully, it will be work. more documentation please visit laravel documentation

Running same query in 2 different views: What's the proper way?

Just getting started into laravel and need to run the same db query for 2 different views, I know I could just create 2 controllers and perform the same query in both passing it to each view.
But, is that the proper way? Or is there a way without repeating my code?
Thanks!
Edit:
I have the following function inside a controller:
protected function getLocation($url)
{
$match = ['url' => $url];
$location = DB::table('location')->where($match)->first();
if (!$location) {
abort(404);
}
return $location;
}
the controller is returning that data to a view:
public function showsubcatandlocation($service)
{
$category = $this->getCat($service);
$location = $this->getLocation($category);
$id = $category->id;
$locID = $location->id;
$profiles = $this->getProfileswLoc($id, $locID);
return view('category', ['profile' => $profiles]);
}
What's the proper way to reuse the getLocation function? Or should I just copy it in the new controller? I just need to use it in those 2 views.
maybe scope Query helps?
class Location extends Model
{
public function scopeMatch($query, $url)
{
return $query->where('url', $url);
}
}
And then your two controllel methods will be
$location = Task::match($url)->first();
if (!$location) {
abort(404);
}
return $location;
$category = $this->getCat($service);
$location = Task::match($category['url'])->first();
$id = $category->id;
$locID = $location->id;
$profiles = $this->getProfileswLoc($id, $locID);
return view('category', ['profile' => $profiles]);

zend Pagination without fetching query again for each page

Is it possible to use zend pagination without calling the query every time i request a page from the pager?
When I hit a page number from the pager a request to the zzAction below is done and the query is fetched again. My query is huge and I don't want to fetch the query all over again. Am I missing something in the code.
Code:
Controller:
public function getOnePageOfEntries($array, $page=1) {
$paginator = Zend_Paginator::factory($array);
$paginator->setItemCountPerPage(6);
$paginator->setCurrentPageNumber($page);
return $paginator;
}
public function zzAction() {
...
$tt= $this->yyObject->xx(....);
$paginator = $this -> getOnePageOfEntries($tt, $page);
$this->view->paginator = $paginator;
}
Model:
public function xx(...){
try{
...
$stmt = $this->prepare("CALL sp_yy(...)");
....
$stmt->execute();
$result = $stmt->fetchAll();
if (is_null($result)) {
return null;
}
return $result;
}catch (ErrorsException $obj){
echo $obj;exit;
}//end try
}
View:
<?php
$config = Zend_Registry::get('appsConfig');
?>
<?php if (count($this->paginator)){ ?>
<?php foreach($this->paginator as $cc){ ?>
<?php echo $cc['id'] . '/';?>
<?php } ?>
<?php } ?>
<?php echo $this->paginationControl($this->paginator,
'Sliding','ff/my_pagination_control.phtml'); ?>
using Zend_Paginator_Adapater_DbSelect();
example:
$adapter = new Zend_Paginator_Adapter_DbSelect($data); //$data is database query
$pagination = new Zend_Paginator($adapter);
See more here:
Zend_Paginator_Adapter_DbSelect
Your current code artificially limits the utility of the array adapter and forces you to execute the whole query for every page. What you need to accomplish in your controller actions that consume this paginator is to only execute the query if the data doesn't already exist. Maybe something similar to:
//consider this to psuedocode as it has not been tested a represents an idea
public function zzAction()
{
//get page number
$page = $this->getRequest()->getParam('page');
//set session namespace, probably better to do this in init() method or bootstrap
$session = new Zend_Session_Namespace('paged')
//test for presence of persisted array
if (!isset($session->paginator)) {
//perform query
$arrayToPage = $this->yyObject->xx(....);
//persist result array
$session->paginator = $arrayToPage;
} else {
//retrieve persisted array
$arrayToPage = $session->paginator;
}
$paginator = $this -> getOnePageOfEntries($arrayToPage, $page);
$this->view->paginator = $paginator;
}
Using the DbTableSelect or DbSelect paginator adapter is often far more effiecient as it only queries for the data need to populate a specific page. This is very useful when your user wants to go form page 1 to page 7 ...
Another consideration when using a paginator is custom entity models. This is fairly easy to deal with in ZF:
<?php
class Record_Model_Paginator_Record extends Zend_Paginator_Adapter_DbTableSelect
{
//override getItems to customize the adapter to use a specific mapper to create entities
public function getItems($offset, $itemCountPerPage)
{
$rows = parent::getItems($offset, $itemCountPerPage);
$record = array();
foreach ($rows as $row) {
//initiate mapper
$recordEntity = new Application_Model_Mapper_Record();
//create entity models
$record[] = $recordEntity->createEntity($row);
}
//returns an array of objects, similar to a Zend_Db_Rowset object
return $record;
}
}
I hope this helps.

CodeIgniter: How to pass variables to a model while loading

In CI, I have a model...
<?php
class User_crud extends CI_Model {
var $base_url;
var $category;
var $brand;
var $filter;
var $limit;
var $page_number;
public function __construct($category, $brand, $filter, $limit, $page_number) {
$this->base_url = base_url();
$this->category = $category;
$this->brand = $brand;
$this->filter = $filter;
$this->limit = $limit;
$this->page_number = $page_number;
}
public function get_categories() {
// output
$output = "";
// query
$this->db->select("name");
$this->db->from("categories");
$query = $this->db->get();
// zero
if ($query->num_rows() < 1) {
$output .= "No results found";
return $output;
}
// result
$output .= "<li><a class=\"name\">Categories</a></li>\n";
foreach ($query->result_array as $row) {
$output = "<li>{$row['name']}</li>\n";
}
return $output;
}
while I am calling this in my controller...
<?php
class Pages extends CI_Controller {
// home page
public function home() {
}
// products page
public function products($category = "cell phones", $brand = "all", $filter = "latest") {
// loading
$this->load->model("user_crud");
//
}
Now, How can I pass the $category, $brand and $filter variables to the user_crud model while loading/instantiation?
You shouldn't be using your model like this, just pass the items you need for the functions you require:
$this->load->model("user_crud");
$data['categories'] = $this->user_crud->get_categories($id, $category, $etc);
I would suggest (after seeing your code) that you study the fantastic codeigniter userguide as it has really good examples, and you just went a totally different way (treating model like an object). Its more simple sticking to how it was designed vs what you are doing.
You can not. A better idea would be to setup some setters in your model class along with some private vars and set them after loading the model.
if you return $this from the setters you can even chain them together like $this->your_model->set_var1('test')->set_var2('test2');

how to instantiate a class with result object in Codeigniter?

The documentation for result() says that we can pass the name of a class to instantiate for each result object: http://codeigniter.com/user_guide/database/results.html
I'm can't figure out correct way to do so.I need to pass few fields from the result object to the constructor.
$query = $this->db->query("SELECT * FROM users;");
foreach ($query->result('User') as $user)
{
echo $row->name; // call attributes
echo $row->reverse_name(); // or methods defined on the 'User' class
}
please let me know if there are better ways!
You can create a static Class method in your User class that creates a user or users instances. You will need to add the appropriate instance vars to the User class.
var $username = FALSE;
var $password = FALSE;
public static function get_user_by_id($id)
{
$CI =& get_instance();
$query = $CI->db->get_where('users', array('id' => $id));
$user = $query->row(0, 'User');
return $user;
}
In the example I'm getting a reference to the CodeIgniter instance to access the database. Since you can't access the database from a Class method since it is not an object instance.
You can't.
The object instantiated can't be passed any arguments, which means you need to create a method you can use to pass these fields to the object which is instantiated:
$query = $this->db->query("SELECT * FROM users;");
foreach ($query->result('User') as $user)
{
$row->init_my_fields('field1', 'field2'); //instead of passing the fields through the __construct()
echo $row->name; // call attributes
echo $row->reverse_name(); // or methods defined on the 'User' class
}
from codeigniter documentation
$query = $db->query("SELECT * FROM users LIMIT 1;");
$row = $query->getRow(0, 'User'); // or ->row(0, 'User') in CI 3
from codeigniter /system/database/DB_result.php
public function custom_result_object($class_name)
{
...
if ($_data !== NULL)
{
for ($i = 0; $i < $c; $i++)
{
$this->custom_result_object[$class_name][$i] = new $class_name();
foreach ($this->{$_data}[$i] as $key => $value)
{
$this->custom_result_object[$class_name][$i]->$key = $value;
}
}
return $this->custom_result_object[$class_name];
}
...
}
I believe this means that CI define new class with empty constructor from the wanted class "should be available to instantiate in the scope" , and tries to set its properties with the values from the row result and then returns it

Resources