I am trying to implement a widgets library using load->view. I know I can use include to call directly the file and avoid the vars cache issues but just wondering why it does not work.
Here is how I have structured my code:
My Controller:
class Page extends MY_Controller {
public $data = array();
public function __construct() {
parent::__construct();
...
$this->load->library('widgetmanager');
}
public function index($slug = '') {
echo $this->widgetmanager->show(2);
echo $this->widgetmanager->show(1);
}
}
My Library
class WidgetManager
{
private $CI;
public function __construct()
{
$this->CI = & get_instance();
}
public function show($widget_id) {
$data = array();
$widget_id = (int)$widget_id;
$this->CI->db->select('*');
$this->CI->db->from('widget');
$this->CI->db->where('id', $widget_id);
$query = $this->CI->db->get();
$item = $query->row_array();
$data['widget_title'] = $item['title'];
$data['widget_content'] = $item['content'];
$widget = $this->CI->load->view('widget/'.$item['source'], $data, TRUE);
$data['widget_title'] = '';
$data['widget_content'] = '';
$this->CI->load->view('widget/'.$item['source'], $data);
return $widget;
}
}
widget 1: Calls widget/content
widget 2: Calls widget/banner
What is happening is, the vars set on the first widget call (they are same name as second widget call), get cached, meaning values from the first call are passed to same call. It is weird because are different views.
I have tried:
Using clear_vars(): $this->CI->load->clear_vars(), before and after doing load->view on the library.
Calling load->view with empty array, null, etc
Tried to add a prefix with the widget slug to the vars (that works, but I have to send in some way the prefix to the view, so it is not possible due cache issue)
Any ideas?
Here is what should work.
(I took the liberty of simplifying your database call making it require much less processing.)
public function show($widget_id)
{
$data = array();
$widget_id = (int) $widget_id;
$item = $this->CI->db
->get_where('widget', array('id' => $widget_id))
->row_array();
$data['widget_title'] = $item['title'];
$data['widget_content'] = $item['content'];
$widget = $this->CI->load->view('widget/'.$item['source'], $data, TRUE);
//clear the cached variables so the next call to 'show()' is clean
$this->CI->load->clear_vars();
return $widget;
}
On further consideration The call $this->CI->load->clear_vars(); is probably pointless because each time WidgetManager::show() is called the $data var is recreated with exactly the same keys. When the $data var is passed to load->view the new values of $data['widget_title'] and $data['widget_content'] will replace the values in the cached vars using those keys.
Related
Needing help understanding codeigniter 3 behavior
I'm not understanding the controller behavior very well and I ask for help
class Simulado extends CI_Controller {
function __construct(){
parent::__construct();
$this->load->helper('url');
$this->load->helper('funcoes_helper');
$this->load->helper('file');
$this->load->library('session');
$this->load->library('controle_acesso');
$this->load->model('resumoapp_model', 'resumo');
$this->load->model('homeapp_model', 'homeapp');
$this->load->model('simulado_model', 'simulado');
//permissão para acessar app
$this->controle_acesso->acesso();
$this->output->enable_profiler(TRUE);
}
public function index() {
$dados = '0'//todas as materias;
$bdinsert = $this->simulado->set_bd($dados);
$this->load->view('prova',$dados)
}
public function materia () {
$dados = 1; //idamateria
$bdinsert = $this->simulado->set_bd($dados);
$this->load->view('prova',$dados)
}
}
model
public function set_bd ($dados) {
$data = [
'id_mat' = $dados
];
$this->db->insert('simulados', $data);
}
routes.php
$route['default_controller'] = 'home';
$route['404_override'] = 'my404';
$route['translate_uri_dashes'] = FALSE;
$route['app'] = "/app/home";
$route['site'] = "/home";
when accessed through the link http://localhost/escola/app/simulado, the system behaves in the desired way, it writes the value zero once in the database, for example.
accessing the url we have the method of the class, simulated, http://localhost/escola/app/simulado/materia/1/exatas-matematica calls the method in the correct way, but when writing to the database it writes the code of the matter.
I did a test and put the same code of the article method in the index and called the url, and it worked perfectly, writing only once the code of the article in the database.
I need to know why it is recording 3 times in the database when accessing the url is a method of the class and has parameters.
I'm using this library in Codeigniter to retrieve multiple result sets from stored procedures :
class Multi_Results
{
private $CI, $Data, $mysqli, $ResultSet;
/**
* The constructor
*/
function __construct()
{
$this->CI =& get_instance();
$this->Data = '';
$this->ResultSet = array();
$this->mysqli = $this->CI->db->conn_id;
}
public function GetMultiResults($SqlCommand)
{
/* execute multi query */
if (mysqli_multi_query($this->mysqli, $SqlCommand)) {
$i=1;
do
{
if ($result = $this->mysqli->store_result())
{
while ($row = $result->fetch_assoc())
{
$this->Data[$i][] = $row;
}
mysqli_free_result($result);
}
$i++;
}
while ($this->mysqli->more_results() && $this->mysqli->next_result());
}
return $this->Data;
}
}
I'm calling the procedure from the controller like
$result_array = $this->multi_results->GetMultiResults("CALL procedure_name($input_1, '$input_2')");
It does what it is supposed to do. The problem arises when I call 2 DIFFERENT procedures from the controller one after another and assign the results to different variables.
When I var_dump the second (last) result, it contains also the result set from the 1st result.
I have checked the connection dbdriver in database.php (it is set to MSQLI), I tried to implement some suggestions like :
CodeIgniter active records' problems calling multiple stored procedures and Calling a stored procedure from CodeIgniter's Active Record class
They both propose a solution with 'mysqli_free_result' however that is already done in the addon library (as you can see in the code snippet above).
Any suggestion will be highly appreciated!
Initiate $this->data = '' into the function GetMultiResults() instead into constructor.
I think this will solve your problem.
My master layout here's below and working fine. I just want little bit more passing a default variable with this master layout that I can get in every pages.
class MY_Controller extends CI_Controller {
public $layout;
function __construct() {
parent::__construct();
$this->layout='layout/master';
}
}
I need to pass variable like below:
function __construct() {
parent::__construct();
$data['msg'] = $this->session->flashdata('usermsg');
$this->layout=('layout/master',$data);
}
How do I get this.
If you are loading up the data dynamically from the controller with the help of $this->layout you can send the data like this.
Method 1:
If you are using the general method to load the data to the view you can use this method.
$this->load->view('profile_view', $data);
This will load the profile_view page along with the $data as you passs into it with the help of array()
Method 2:
If you have created a master Layout and you are passing the data from the controller to the Master Layout you need to do like this.
<?php
public function master_layout () {
$this->template['header'] = $this->load->view('include/header', $this->Front_End_data, true);
$this->template['navigation'] = $this->load->view('include/navigation', $this->Front_End_data, true);
$this->template['center'] = $this->load->view($this->middle, $this->Front_End_data, true);
$this->template['footer'] = $this->load->view('include/footer', $this->Front_End_data, true);
$this->load->view('include/index', $this->template);
?>
In this code the below line alone will be loaded dynamically based on the page which you call in the master Layout.
$this->template['center'] = $this->load->view($this->middle, $this->Front_End_data, true);
In order to pass the data to this center layout you can use the funciton like this.
$data['msg'] = 'Success';
$this->template['center'] = $this->load->view ($this->middle = 'pages/view_oage',$data, true);
$this->master_layout();
And in the page you can get the data to be printed using the foreach loop as follows.
foreach($msg as $value)
{
echo $value;
}
I have been wondering what is the right way to write code in OO style in model. Certainly you can have a function that retrieve data from DB and then map to model-level variables. This approach, however, becomes counterintuitive when you have other function in model trying to get other data from BD. For example:
class User extends CI_Model {
$id, $name, $age .... ;
public function get_user_from_db_with_id($id) {
...
// get data and map to variable.
}
public function get_all_users() {
// return all users in db
}
}
somewhere in controller:
$user = new User();
$ben = $user->get_user_from_db_with_id($id);
// this does not make sense!!
$all_user = $ben->get_all_users();
Any thought or comment?
Thanks in advance!
I had to make a similar decision and opted for this (trimmed for clarity)
class UserModel extends MY_Model
{
public $UserID = 0;
public $CustomerID = null;
public $FirstName = '';
public $LastName = '';
public $EmailAddress = '';
public $Password = null;
public $UserGroupID = true;
function __construct()
{
parent::__construct();
}
private function get($id)
{
$row = $this->get($id);
if ($row !== null)
{
$this->dbResultToObject($row, $this);
}
}
// Return an array of User objects
public function get_list($deleted = false, $userIDToInclude = null)
{
$params = array(null, $deleted, $userIDToInclude);
$query = $this->db->call("spUserGet", $params);
$users = array();
foreach ($query->result() as $row)
{
$user = new UserModel();
$this->dbResultToObject($row, $user);
$users[] = $user;
}
return $users;
}
// Other Methods (Validate, Save etc)
}
I use a mixture of public, protected and private properties so that the reflection code I've written to map the properties from the DB results and to the DB sproc calls then only includes the public properties and prevents too many parameters being sent. But that's getting off-topic so my controller then just looks like:
class Users extends MY_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('UserModel', 'user');
}
....
}
Then a list can be retrieved with
$users = $this->user->get_list();
And a single record with
$user = $this->user->get($userID);
i'm a big fan of thinking about the design in terms of "roles" - not resources. so a "User" is going to be able to get their own Profile. but its only going to be an "Admin" who is able to get All User Profiles.
so that distinction and important separation between what a User can do - get one record - and what an Admin can do - get all records - starts by having separate controllers for each. The User Controller methods are based upon verifying a single user and granting them access to one record. The Admin Controller methods are based upon verifying an admin and granting them access to all records. And this makes sense even from a URL design standpoint - you want your admin area clearly separate.
This separation at the controller makes everything simpler and easier. When you are resource oriented you are constantly checking the credentials in every method and even in your views. Views should be as simple as possible and not be tasked with "is this person an admin"? When you are role oriented - you check the credentials in the controller - and then your methods, the models, and the views are appropriate for what that 'role' needs to accomplish.
Since you are think about OO programming, i think you need to think: what does this class represent?
each instance means one user?
each instance means one user-data-generator?
if it's the first case, it makes sense this class has attributes like $id, $name, $age ....
and the following codes make sense
$user = new User();
$ben = $user->get_user_from_db_with_id($id);
if it's the second case, it shouldn't have the attributes like $id, $name, $age in you sample.
and these codes
$all_user = $ben->get_all_users();
should be replaced with this
$all_user = $user->get_all_users();
I am new to CI and what I want to do is to have a class level variable (which e.g is an array). But it seems like CI, despite all high bragging, doesn't support this feature. Nothing has been mentioned in the user guide about it. There is a heading called private functions and variables but the text has been seemingly kept silent regarding variables.
I want to have something like :
class OrderStats extends CI_Controller {
protected $arr_CoreCountry = ('0'=>'uk', '1'=>'us');
public function __construct()
{
parent::__construct();
// Your own constructor code
}
public function index()
{
$this->load->model('orders', '', TRUE);
//$data['result'] = $this->Testmodel->get_entries();
$data['result'] = $this->Testmodel->get_reports();
$this->load->view('test', $data);
}
public function getOrderStats()
{
$this->load->model('Orderstatsmodel', '', TRUE);
//$data['result'] = $this->Testmodel->get_entries();
foreach ($arr_CoreCountry as $key => $value)
{
$data['result'] = $this->Orderstatsmodel->get_orderStats($key);
}
// $data['result'] = $this->Orderstatsmodel->get_orderStats(0);
$this->load->view('orderstats', $data);
}
Remember, when I declare $arr_CoreCountry variable at the place as it is in this post, I constantly see a syntax error message.
When I place it some where inside any function then of course, it gets out of scope and I keep getting an error messag that $arr_CoreCountry is an undefined variable.
So the question is where do I define it?
Expect a quick response as half of my day has been wasted just because of this s*** from codeigniter.
This should work:
class OrderStats extends CI_Controller {
protected $arr_CoreCountry = array('0'=>'uk', '1'=>'us');
public function getOrderStats()
{
$this->load->model('Orderstatsmodel', '', TRUE);
//$data['result'] = $this->Testmodel->get_entries();
foreach ($this->arr_CoreCountry as $key => $value)
// etc
}
you are omitting the $this-> in your original code.
Edit
Here was my test code ~
class Testing extends CI_Controller {
protected $foo = array('test'=>'foo', 'bar'=>'baz');
function index() {
foreach($this->foo as $k => $v) {
echo $k . ' = ' . $v . '<br />';
}
}
}
// outputs:
test = foo
bar = baz
perhaps you can post your syntax errors as they appear to be missing from your original post.
You have a syntax array declaration error. Please try to declare array like this:
protected $arr_CoreCountry = array('0'=>'uk', '1'=>'us');
Please check out this site for array manual: http://php.net/manual/en/language.types.array.php
I solved the problem myself.
There are two things which I changed
protected $arr_CoreCountry = ('0'=>'uk', '1'=>'us');
was changed to
var $arr_CoreCountry = array(0=>'se', 1=>'fi',2=>'de');
and
foreach ($arr_CoreCountry as $key => $value)
was changed to
foreach ($this->arr_CoreCountry as $key => $value)
I was missing $this but when I put it there, it was still not working. When I changed protected to var, it worked.
Thanks everyone for your input...