CodeIgniter - cannot set routing - php

I have a problem with CI. I have a model:
public function Game($id) {
$id = (int)$id;
$q = $this -> db -> get_where('games', array('id' => $id));
return $q -> row_array();
}
Controller for it:
public function index($gameID) {
$data['game'] = $this->games_model->Game($gameID);
$this -> load -> view('games/game', $data);
}
And a problem ;) I've set my routing as follows:
$route['games/(:num)'] = 'games/game/$1';
$route['games'] = 'games/game/game';
But it doesn't work at all. My controller dir is games/game.php (with function Game inside). My problem is - how can I pass $id for it? I am very new to CI, but I couldn't find solution for this in docs.

$route['games'] = 'games/game/index'; // Folder/Controller/Function
$route['games/(:num)'] = 'games/game/index/$1'; // Folder/Controller/Function/Method
$route['games/(:num)/(:any)'] = 'games/game/index/$1/$2';
If you want to use slug, url_title($title, 'underscore', TRUE) it help you

You can use either remap or you will have to modify your routes path again. Take a look at this question, that's been asked here.

Related

Only variable to be assigned by reference for $model and $modelproduct

For this code, its stating that only variable to be assigned by reference for $model and $modelproduct. I tried to look at some other example but could not make out of it.
Can any help on same?
public function display($tpl = null)
{
$app = JFactory::getApplication();
$user = JFactory::getUser();
// Push a model into the view
$model = &$this->getModel();
$modelProduct = &$this->getModel( 'pages' );
$MSG="";
$this->assignRef('MSG' , $MSG);
parent::display($tpl);
}
You use &$this in your code. It means that the result of the function should point to a specific location in memory and that could not be.
I cannot understand why you would like to do that but if think it is a bad understanding of reference. My solution is to remove & as it is unuseful in that case.

Normal calling object inside Model VS fetchAll()

Im new to zendframework & zend db..any help will be great!!
(Normal Way)
Lets say i want to get data..so im using this
Inside Controller
$db = new Studentfinance_Model_DbTable_FeeItem();
$data =$this->db->getDate();
Inside Model
protected $_name = 'tbl_foo_foo';
protected $_primary = "foo_id";
public function getData() {
$db = Zend_Db_Table::getDefaultAdapter();
$selectData = $db->select()
->from(array('a'=>$this->_name))
->joinLeft(array('c'=>'tbl_bar'), 'c.idBar = a.id',array('DefinitionDesc','Status'))
->group('a.id')
$fc_cat = $db->fetchAll($selectData);
return($fc_cat);
}
For Above line of code...i understand the way its work..
But for below..i have a bit problem to understand..same concept..the purpose to get the data
inside controller/form
$feeCategoryDb = new Studentfinance_Model_DbTable_FeeCategory();
$listData = $feeCategoryDb->fetchAll();
i try to find function fetchAll()...but i dont find it inside Model FeeCategory...can someone explainn this
$feeCategoryDb->getData() already sets up the query and runs "fetchAll" and returns the results. So all you need to do is:
$feeCategoryDb = new Studentfinance_Model_DbTable_FeeCategory();
$listData = $feeCategoryDb->getData();

PHP OOP code is failing due to syntax errors?

Before I ask my question I want to make sure a few things are clear:
1) I read the official PHP manual on OOP (intro, basics, inheritance, properties and so on) It seems im honestly not getting something. Im on it for hours now and fixed a few things there and then but new errors are popping up.
2) I read the error messages Missing argument 1 for Main::__construct() and Undefined variable: array. This means my $start variable is NULL.
3) I did do a few searches on stackoverflow either it is not fully related or very hard for me understand whats going on since the example code is so complex (Not the best thing for a starter).
My question: Why is the below code not working? I would really appreciate why it is failing and what I have to consider.
class Main {
protected $config;
protected $start;
function __construct($arr) {
if(!isset($this -> start)) {
if ($arr['secure']){
$this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini');
$this -> start = mysqli_connect($this -> config['host'], $this -> config['username'],
$this -> config['password'], $this -> config['database']);
}
else {
$this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']);
}
}
if($this -> start == false) {
return mysqli_connect_error();
}
}
}
$Main = new Main($array = ["host" => '', "username" => '', "password" => '', "database" => '',
"errors" => false, "secure" => true]);
class Test extends Main {
public function sample() {
$query = "SELECT id, user,
FROM users";
$result = mysqli_query($Main -> start , $query);
$row = mysqli_fetch_array($result);
echo $row['user'];
}
}
$x = new Test();
$x -> sample();
So here's what happens on run time:
$Main = new Main(...);
OK, you may get a connection there if those details are filled in, but there is an issue in determining whether you made a successful connection or not. See below for more info, but $Main is important to note for now.
$x = new Test();
Class Test extends your class Main.
Your class Test therefore inherits the class Main's constructor, which requires an argument. The argument isn't provided, so it generates a warning.
To account for this, make $arr optional if you're not always going to be passing it:
function __construct($arr = array())
Then check if it exists by using isset on the index:
if(isset($arr['secure'])) // ...
Fast forward, because you haven't provided $arr, you will not be able to successfully connect to your DB. According to mysqli::__construct(), which mysqli_connect is an alias of, it will try to return an object ("which represents the connection to a MySQL Server.").
Now, take a look at these lines:
$this -> start = mysqli_connect( ... )
// ...
if ($this -> start == false) {
You must check against the return's connect_error attribute (or mysqli_connect_error()) to verify if the connection worked or not.
Thanks to the comments below, you should ALSO check for a false assignment, as mysqli_connect has been known to generate a warning and return false too, even though it is not shown on the PHP docs.
Let's continue.
$x -> sample();
Test::sample uses mysqli_query which expects the database connection as it's first argument. You attempt this by passing $Main->start.
Unfortunately, $Main is not in your variable scope, and cannot be accessed from inside of that method. What you need to reference is $this->start.
In fact, if this is the only reason you instantiated $Main, then you don't need to at that point. Instead, pass the connection details array through to new Test() instead.
Here's two solutions:
Pass your DB connection details through to $x = new Test();
The instance will then connect to the DB as intended and will be able to run the query.
Separate class Test from class Main, and pass an instance of class Main through your class Test constructor.
Probably the better option. If your Test is meant to be for your query don't have it extend Main, create your Database connection object (new Main(..)) and then pass that through into new Test($Main). In your Test class, create a constructor which accepts the Main class as an argument:
public function __construct(Main $main)
{
$this->db = $main;
}
Allow access to your connection object by making $main's $start attribute public, or by creating a getter function (e.g. getConnection()), then use than in your query:
$result = mysqli_query($this->db->getConnection(), $query);
There's many, many ways you can approach your scenario, it's down to you.
The answers have addressed the initial problems, but I thought I might also offer a few implementation suggestions also.
You are working with two different instances.
// This is one instance
$Main = new Main([...]);
// This is a different instance.
$test = new Test();
Extending a class does not mean that it gets the values from the existing instances of the class. It only means that it gets the same methods (and default properties).
Therefore, your class Test gets the same constructor as Main, meaning you need to send in the array to Test to be able to use instantiate it. In your example, there is no reason to instantiate Main directly at all.
$result = mysqli_query($Main -> start , $query);
to
$result = mysqli_query($this -> start , $query);
That removes the syntax error at least. $this is an introspective variable, it always refers to the current scope of instances.
Check out the comments below
//I suggest to make this class abstract to make sure
//php doesn't let you to instantiate it directly as you did before
abstract class Main {
protected $config;
protected $start;
function __construct($arr) {
if(!isset($this -> start)) {
if ($arr['secure']){
$this -> config = parse_ini_file('C:\xampp\htdocs\project\config.ini');
$this -> start = mysqli_connect($this -> config['host'], $this -> config['username'],
$this -> config['password'], $this -> config['database']);
}
else {
$this -> start = mysqli_connect($arr['host'], $arr['username'], $arr['password'], $arr['database']);
}
}
if($this -> start == false) {
return mysqli_connect_error();
}
}
}
class Test extends Main {
public function sample() {
$query = "SELECT id, user,
FROM users";
//Here you should use $this instead of $Main as you can access protected
//properties of the parent from the child class.
$result = mysqli_query($this -> start , $query);
$row = mysqli_fetch_array($result);
echo $row['user'];
}
}
//Instantiate Test class instead of Main as it inherits Main anyway
//Your code also had a typo in the constructor argument.
$x = new Test(array("host" => '', "username" => '', "password" => '', "database" => '', "errors" => false, "secure" => true));
$x -> sample();
Please not that I didn't check the mysql part of your code - just an OOP structure

Codeigniter URL remapping strategy

I'm working on a project built in codeigniter that makes heavy use of routes and the remap function to rewrite urls. The current implementation is confusing and messy.
Essentially this is what the designer was trying to accomplish:
www.example.com/controller/method/arg1/
TO
www.example.com/arg1/controller/method/
Can anyone suggest a clean way of accomplishing this?
This actually only needs to happen for one specific controller. It's fine if all other controllers need to simply follow the normal /controller/model/arg1... pattern
Just to give you an idea of how the current code looks here is the 'routes' file: (not really looking into any insight into this code, just want to give you an idea of how cluttered this current setup is that I'm dealing with. I want to just throw this away and replace it with something better)
// we need to specify admin controller and functions so they are not treated as a contest
$route['admin/users'] = 'admin/users';
$route['admin/users/(:any)'] = 'admin/users/$1';
$route['admin'] = 'admin/index/';
$route['admin/(:any)'] = 'admin/$1';
// same goes for sessions and any other controllers
$route['session'] = 'session/index/';
$route['session/(:any)'] = 'session/$1';
// forward http://localhost/ball/contests to controller contests method index
$route['(:any)/contests'] = 'contests/index/$1';
// forward http://localhost/ball/contests/vote (example) to controller contests method $2 (variable)
$route['(:any)/contests/(:any)'] = 'contests/index/$1/$2';
// forward http://localhost/ball/contests/users/login (example) to controller users method $2 (variable)
$route['(:any)/users/(:any)'] = 'users/index/$1/$2';
// if in doubt forward to contests to see if its a contest
// this controller will 404 any invalid requests
$route['(:any)'] = 'contests/index/$1';
$route['testing/'] = 'testing/';
And the remap function that goes with it:
public function _remap($method, $params = array()){
// example $params = array('ball', 'vote')
// params[0] = 'ball', params[1] = 'vote'
/*
* Write a detailed explanation for why this method is used and that it's attempting to accomplish.
* Currently there is no documentation detailing what you're trying to accomplish with the url here.
* Explain how this moves the contest name url segment infront of the controller url segment. Also
* explain how this works with the routing class.
* */
$count = count($params);
if($count == 0){ // no contest specified
redirect('http://messageamp.com');
return;
}
$contest_name = $params[0];
unset($params[0]); //remove the contest name from params array because we are feeding this to codeigniter
if($count < 2) // no method specified
$method = 'index';
else{
$method = $params[1];
unset($params[1]);
}
//We need to scrap this, lazy-loading is a best-practice we should be following
$this->init(); //load models
//make sure contest is valid or 404 it
if(!$this->central->_check_contest($contest_name)){
show_404();
return;
}
$this->data['controller'] = 'contests';
$this->data['method'] = $method;
$this->data['params'] = $params;
// call the function if exists
if(method_exists($this, $method)){
return call_user_func_array(array($this, $method), $params);
}
show_404(); // this will only be reached if method doesn't exist
}
To get something like this:
www.example.com/controller/method/arg1/ TO www.example.com/arg1/controller/method/
You could do this in your routes.php config:
$route['(:any)/(:any)/(:any)'] = "$2/$3/$1";
However, if you want to have all of your other classes stick to the default routing, you would need to create routes for each of them to overwrite this default route:
$route['controller_name/(:any)'] = "controller_name/$1";

PHP and Codeigniter - How do you check if a model exists and/or not throw an error?

Example #1
bschaeffer'sanswer to this question - in his last example:
$this->load->model('table');
$data = $this->table->some_func();
$this->load->view('view', $data);
How do you handle this when 'table' doesn't exist?
Example #2
try {
$this->load->model('serve_' . $model_name, 'my_model');
$this->my_model->my_fcn($prams);
// Model Exists
} catch (Exception $e) {
// Model does NOT Exist
}
But still after running this (obvously the model doesn't exist - but sometimes will) it fails with the following error:
An Error Was Encountered
Unable to locate the model you have specified: serve_forms
I am getting this function call by:
1) Getting some JSON:
"model_1:{"function_name:{"pram_1":"1", "pram_2":"1"}}
2) And turning it into the function call:
$this->load->model('serve_' . "model_1", 'my_model');
3) Where I call:
$this->my_model->function_name(pram_1=1, pram_2=1);
SOLUTION
The problem lies in the fact that CodeIgniter's show_error(...) function displays the error then exit; ... Not cool ... So I overrode: model(...) -> my_model(..) (you'll get errors if you just override it) and removed the show_error(...) because for some reason you can't override it - weird for Codeigniter). Then in my_model(...) made it throw an Exception
My personal opinion: the calling function should return
show_error("message"); where show_error returns FALSE --- that or
you could take out the exit; - and make show_error(...)
overridable
You can see if the file exists in the models folder.
$model = 'my_model';
if(file_exists(APPPATH."models/$model.php")){
$this->load->model($model);
$this->my_model->my_fcn($prams);
}
else{
// model doesn't exist
}
Maybe this helper function will help you to check if a model is loaded or not.
function is_model_loaded($model)
{
$ci =& get_instance();
$load_arr = (array) $ci->load;
$mod_arr = array();
foreach ($load_arr as $key => $value)
{
if (substr(trim($key), 2, 50) == "_ci_models")
$mod_arr = $value;
}
//print_r($mod_arr);die;
if (in_array($model, $mod_arr))
return TRUE;
return FALSE;
}
source reference
Don't foget that your application may use pakages. This helper function look through all models (even in packages included in your CI app).
if ( ! function_exists('model_exists')){
function model_exists($name){
$CI = &get_instance();
foreach($CI->config->_config_paths as $config_path)if(file_exists(FCPATH . $config_path . 'models/' . $name . '.php'))return true;
return false;
}
}
Cheers
#Endophage No you do not have to explicitly state what the model you are loading will be. They can be loaded dynamically.
Example:
$path = 'path/to/model/';
$model = 'My_model';
$method = '_my_method';
$this->load->model($path . $model);
return $this->$model->$method();
So you could have a single controller that uses the URL or POST vars.
I use this concept a lot with ajax calls. So OP's question is very valid. I would like to make sure that the model exists before I try to load it.

Categories