CodeIgniter Hooks for Active Record library - php

I need some help to understand CodeIgniter's hook logic to adapt the code to my needs.
The page : https://www.codeigniter.com/user_guide/general/hooks.html
In fact, I had to modify the database driver for MySQL from this :
function _from_tables($tables)
{
if ( ! is_array($tables))
{
$tables = array($tables);
}
return '('.implode(', ', $tables).')';
}
to this :
function _from_tables($tables)
{
if ( ! is_array($tables))
{
$tables = array($tables);
}
return implode(', ', $tables);
}
I made this mod to use UNION queries using Active Record library.
Can someone help me to make a hook in order to prevent my modification from being overwritten when I update the core system ?
Thanks in advance !

You can find the instructions for extending the db drivers on the CodeIgniter Wiki - Extending Database Drivers
The solution comes in 3 simple steps:
1) Extend your loader class by creating the file MY_Loader.php. Put it
into your libraries directory in the application path (or if you are
using CI 2.x.x then put it into application\core\ path):
2) Add the following function to your MY_Loader class:
3) Create your Database driver extension class, that you name
MY_DB_mysql_driver.php (or substitute the mysql part for whatever
driver you use - do that also for the classnames in the code below!).
Put this file also in your applications libraries directory:
Your custom DB driver will look like this
class MY_DB_mysql_driver extends CI_DB_mysql_driver {
function __construct($params){
parent::__construct($params);
log_message('debug', 'Extended DB driver class instantiated!');
}
function _from_tables($tables)
{
if ( ! is_array($tables))
{
$tables = array($tables);
}
return implode(', ', $tables);
}
}

Related

No records found ...Agiletoolkit and Oracle. Grid/CRUD elements

I am trying to test around Agile Toolkit with oracle, after seting up a model and trying to show a grid it says "No records found"...
Let me tell you what I did, since i've been guessing most of all configuration as I found no guides for oracle.
My Oracle connection string in agiletoolkit config-default.php file looks like this:
$config['dsn']= array( 'oci:dbname=localhost/MYDATABASE', 'MYUSER', 'MYPASSWORD' );
To fix the driver not found error, I enabled extension=php_pdo_oci8.dll in the php.ini file from my apache installation.
Then there was an error about a missing "oci.php", to solve that I had to create my own file like this:
class DB_dsql_oci extends DB_dsql {
function limit($cnt,$shift=0){
$cnt+=$shift;
$this->where('NUM_ROWS>=',$shift);
$this->where('NUM_ROWS<',$cnt);
return $this;
}
function render_limit(){
return '';
}
}
and placed it at: ...atk4\lib\DB\dsql
To fix the special chars error from oracle , I set line 59 on /atk4/lib/DB/dsql.php to empty string like this: public $bt='';
I manage to run the database test, and it says "Successfully connected to database."
Then I created a model "lib\Model\Mytable.php" like this:
<?php
class Model_Mytable extends Model_Table {
public $table = "MYTABLE";
function init(){
parent::init();
$this->addField('ID');
$this->addField('NAME');
$this->addField('INIDATE');
$this->addField('ENDDATE');
}
?>
After that, I made a new page and tried to use the model like this:
<?php
class page_test extends Page {
function init(){
parent::init();
$form = $this->add('Grid');
$form->setModel('Mytable');
}
}
?>
After refreshing the browser, it will show the grid saying " No Records found"
I wonder whats happening, that table has records no doubt, all data is committed, and im sure oracle is parsing queries because if I miss a column name an oracle error will raise.
Any clue?
This is how you can simply set DSQL as your View (Grid for example) data source:
class page_test extends Page_Basic
{
function init()
{
parent::init();
// DSQL
$q = $this->api->db->dsql();
$q->table('MYTABLE')
->field('DNAME')
->field('INIDATE');
// Create grid and set DSQL as its data source
$g = $this->add('Grid');
$g->addColumn('DNAME');
$g->addColumn('INIDATE');
$g->setSource($q);
// better add paginator too or your grid can become huge :)
$g->addPaginator();
}
}

New server ignoring capitalization in PHP app

I have worked on a codeigniter 2.1.3 application which was developed on windows running wamp 2.2 (php 5.4.3). I recently uploaded the application to a ubuntu 12.04 server running apache 2.2.22 and php 5.4.6.
My model classes are named like billView.php, categoryModel.php etc. Note the capital letters. The name of the classes inside the php files is also the same. And the name i give when calling the models from controller classes is also the same.
But when I run my app on Ubuntu, I get this error
Unable to locate the model you have specified: billview
The error is thrown from this line:
$this->load->model('billView');
(i.e. php is ignoring the capital letter)
When I rename the model file (only the model filename, class name stays intact) then the error disappears.
How to solve this problem without manually renaming all my files?
From the documentation:
Where Model_name is the name of your class. Class names must have the
first letter capitalized with the rest of the name lowercase. Make
sure your class extends the base Model class.
It's better to follow the naming convention than to work around it.
Hope this helps.
The problem that you are facing is that Windows filesystem (NTFS) is case insensitive, so in windows, billview.php and billView.php are the same file.
On Linux, as you might be guessing now, the typical filesystems (ext2/3/4, xfs, reiserfs...) are case sensitive, and for that reason, billview.php and billView.php are (or may be) different files. In your case, one exists and the other does not.
Inside CodeIgniter autoloader function/method/class/whatever, it is trying to require the file that has the class you are instantiating, so if you tell it that you need the model billview, it will try to require path/to/model/billview.php;, and this file does not exist, so the model doesn't get loaded and then your application fails.
Of course it is recommended to follow a naming convention if there is one as Amal Murali suggests, but it is not the issue here. If all your classes, files, and instances in code had the same capitalization (whether it may be all_lowercase, ALL_UPPERCASE, camelCase or sTuPiD_CaSe) everything would have worked.
So, please refer to your files/class names with the same capitalization as you have created them, and the capitalization in a class name should follow that of the file name it is stored in.
You will have the same problems if your html code refers to files (images, css, js files) in different capitalization for the same reason. The webserver will be looking for image.jpg but it will not exist (the existing file would be Image.JPG for example).
In a related note, variables in php are case sensitive, but functions and classes aren't. despite that, call them always with the right capitalization to avoid problems.
I personally have found this convention in CodeIgniter to make no sense. I wouldn't recommend hacking the CodeIgniter core but you can easily extend the CI_Loader class. Here is mine from CI version 2.2.0.
<?php
class MY_Loader extends CI_Loader
{
/**
* Model Loader
*
* This function lets users load and instantiate models.
*
* #param string the name of the class
* #param string name for the model
* #param bool database connection
* #return void
*/
public function model($model, $name = '', $db_conn = FALSE)
{
if (is_array($model))
{
foreach ($model as $babe)
{
$this->model($babe);
}
return;
}
if ($model == '')
{
return;
}
$path = '';
// Is the model in a sub-folder? If so, parse out the filename and path.
if (($last_slash = strrpos($model, '/')) !== FALSE)
{
// The path is in front of the last slash
$path = substr($model, 0, $last_slash + 1);
// And the model name behind it
$model = substr($model, $last_slash + 1);
}
if ($name == '')
{
$name = $model;
}
if (in_array($name, $this->_ci_models, TRUE))
{
return;
}
$CI =& get_instance();
if (isset($CI->$name))
{
show_error('The model name you are loading is the name of a resource that is already being used: '.$name);
}
//$model = strtolower($model);
foreach ($this->_ci_model_paths as $mod_path)
{
if ( ! file_exists($mod_path.'models/'.$path.$model.'.php'))
{
continue;
}
if ($db_conn !== FALSE AND ! class_exists('CI_DB'))
{
if ($db_conn === TRUE)
{
$db_conn = '';
}
$CI->load->database($db_conn, FALSE, TRUE);
}
if ( ! class_exists('CI_Model'))
{
load_class('Model', 'core');
}
require_once($mod_path.'models/'.$path.$model.'.php');
//$model = ucfirst($model);
$CI->$name = new $model();
$this->_ci_models[] = $name;
return;
}
// couldn't find the model
show_error('Unable to locate the model you have specified: '.$model);
}
}
?>
All I did was copy the the CI_Loader::model method then comment out these two lines
//$model = strtolower($model);
//$model = ucfirst($model);
All you have to do is put the above class in your application/core/ folder and it should work.

Why I can't load models in modules?! [Using HMVC in codeigniter 2.1.2]

I hope someone can help me with this one before I jump off the window. I spent few hours on this one and don't know what am I doing wrong.
Basically, I've installed HMVC in CodeIgniter 2.1.2 and everything works fine, BUT for some reason I can't load models the same way I'm doing it in standard controllers. In the old codeigniter 1.7.1 I could use it simply by invoking $this->load->model('my_model') but now I can't?!
Every single time I'm trying to load model I get this error:
A PHP Error was encountered
Severity: Notice
Message: Undefined property: Special_cart::$db
Filename: core/Model.php
Line Number: 51
I have had installed it step-by-step according to the instructions. I got third_party next to modules folder. In modules I have few modules stored like this:
modules
--boxes
----controller
----models
----views
I invoke module in my code like this:
<?=modules::run('boxes/special_cart/index');?>
My module controller code looks like this:
class Special_cart extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function index()
{
if ($this->session->userdata('cart'))
{
# get product id's and each quantity
$cart_product_list = array_count_values($this->session->userdata('cart'));
# get list of product_id
$product_list = array_keys($cart_product_list);
# get product details
$this->load->model('productmodel');
$this->load->model('stockmodel');
$cart_products = $this->productmodel->cart_get_products_details($product_list);
$final_cart_array = array();
foreach($cart_products as $cart_product){
$product_stock = $this->stockmodel->view_product_stock($cart_product["id"]);
if(empty($product_stock) || $product_stock["UNITS"]<=0)
$cart_product["UNITS"] = 0;
else{
if($cart_product_list[$cart_product["id_web"]]>$product_stock["UNITS"])
$cart_product["UNITS"] = $product_stock["UNITS"];
else{
$cart_product["UNITS"] = $cart_product_list[$cart_product["id_web"]];
}
}
$final_cart_array[] = $cart_product;
}
$refresh_cart_array = array();
foreach($final_cart_array as $cart_product){
for($i=1;$i<=$cart_product["UNITS"];$i++){
$refresh_cart_array[] = $cart_product["id_web"];
}
}
$this->load->view("special_cart",array(
'refresh_cart_array' => $refresh_cart_array,
'final_cart_array' => $final_cart_array
));
} else {
$this->load->view("special_cart",array(
'refresh_cart_array' => NULL,
'final_cart_array' => NULL
));
}
}
}
I've tried every possible solution found on internet - none of them work....
I hope you understand my problem but in case you need some further explanation please ask me. Can anyone help?
Looks like the model you're trying to load wants to connect to the db, but the database driver is not available. If you use database queries in your application, why don't you load the database driver automatically?
Just insert "database" in the "libraries" array in application/config/autoload.php file. Don't forget to insert your database credentials into application/config/database.php.
$autoload['libraries'] = array('database');
If you need database connection just in one single model, load it before trying to access database library.
$this->load->database();
Try loading the model stating the module name as follows
$this->load->model('module_name/productmodel');
Class Models extends MX_Loader{
function getUser($username){
$sql="SELECT * FROM user WHERE username = ? ";
return $this->db->query($sql,array($username))->row();
}
}
you must using extends MX_Loader because i don't know if using CI_Model the database core cant be load in Codeigniter,,,
Try to use extend MX_Controller class (not CI_Contoller like you are doing atm)
Based on what you have wrote in comment above, I figured that you tried to create new instance of DB in module (based on chrises comment).
Do it on constuctor of Special_cart
So update current construct to be like
public function __construct()
{
parent::__construct();
$this->load->database('default');
}
(I'm writing this from top of my head, so check the methods)
Now for sure db driver should be available in your models.
Regarding issue with HMVC I dont think there are any. I'm using HMVC for a while now, and I found no problems in it (working with databases)
I had the same problem and mistake. I missed to extend controllers to MX_Controller. So the solution would be to change CI_Controller to MX_Controller like this:
class Special_cart extends MX_Controller
{
public function __construct()
{
parent::__construct();
$this->load->model('productmodel');
$this->load->model('stockmodel');
}
public function index()
{
if ($this->session->userdata('cart'))
{
# get product id's and each quantity
$cart_product_list = array_count_values($this->session->userdata('cart'));
# get list of product_id
$product_list = array_keys($cart_product_list);
# get product details
$cart_products = $this->productmodel->cart_get_products_details($product_list);
$final_cart_array = array();
foreach($cart_products as $cart_product){
$product_stock = $this->stockmodel->view_product_stock($cart_product["id"]);
if(empty($product_stock) || $product_stock["UNITS"]<=0)
$cart_product["UNITS"] = 0;
else{
if($cart_product_list[$cart_product["id_web"]]>$product_stock["UNITS"])
$cart_product["UNITS"] = $product_stock["UNITS"];
else{
$cart_product["UNITS"] = $cart_product_list[$cart_product["id_web"]];
}
}
$final_cart_array[] = $cart_product;
}
$refresh_cart_array = array();
foreach($final_cart_array as $cart_product){
for($i=1;$i<=$cart_product["UNITS"];$i++){
$refresh_cart_array[] = $cart_product["id_web"];
}
}
$this->load->view("special_cart",array(
'refresh_cart_array' => $refresh_cart_array,
'final_cart_array' => $final_cart_array
));
} else {
$this->load->view("special_cart",array(
'refresh_cart_array' => NULL,
'final_cart_array' => NULL
));
}
}
}
this is also explained in the documentation
https://bitbucket.org/wiredesignz/codeigniter-modular-extensions-hmvc/
, here the quote:
Notes:
To use HMVC functionality, such as Modules::run(), controllers must
extend the MX_Controller class. To use Modular Separation only,
without HMVC, controllers will extend the CodeIgniter Controller
class. You must use PHP5 style constructors in your controllers. ie:
<?php
class Xyz extends MX_Controller
{
function __construct()
{
parent::__construct();
}
}

access to extended class in symfony 1.4

so... I basically follow the practical symfony book, and encountered following problem.
I have properly (i guess) installed sfGuardPlugin, built the models, sqls etc, created user and tried to log in with the username and password entered.
i got the following error message:
Fatal error: Call to undefined method sfGuardUserPeer::retrieveByUsername() in /***/plugins/sfGuardPlugin/lib/validator/sfGuardValidatorUser.class.php on line 53
it looks quite weird to me, because the problematic part of sfGuardValidatorUser class looks like this:
// user exists?
if ($user = sfGuardUserPeer::retrieveByUsername($username))
{
// password is ok?
if ($user->getIsActive() && $user->checkPassword($password))
{
return array_merge($values, array('user' => $user));
}
}
while sfGuardUserPeer has just the empty class:
class sfGuardUserPeer extends PluginsfGuardUserPeer
{
}
that extends PluginsfGuardUserPeer, so i checked it out too:
class PluginsfGuardUserPeer extends BasesfGuardUserPeer
{
public static function retrieveByUsername($username, $isActive = true)
{
$c = new Criteria();
$c->add(self::USERNAME, $username);
$c->add(self::IS_ACTIVE, $isActive);
return self::doSelectOne($c);
}
}
that's the missing function!
so - what is wrong? why doesn't it work?
i have already tried all the solutions found with google, but none of them work :/
finally found it!
the
symfony propel:build-model
task unnecessarily generated the sfGuard classes in the model directory from the schema file located in the plugin directory, while all the classes were already present in the sfGuard folder.
geez, that shouldn't happen in such a well-developed framework and plugin...
Simply put that
public static function retrieveByUsername($username, $isActive = true)
{
$c = new Criteria();
$c->add(self::USERNAME, $username);
$c->add(self::IS_ACTIVE, $isActive);
return self::doSelectOne($c);
}
Code into your sfGuardUserPeer class, this will sort out the issue, I did the same when I got this error, it worked for me..

Zend_Db_Profiler log to file

Is there a simple way to log to queries to a file? I have Firebug profiling working no problem with:
resources.db.params.profiler.enabled = "true"
resources.db.params.profiler.class = "Zend_Db_Profiler_Firebug"
It would be nice to log this to a file with out writing a bunch of code.
Is there a class I can swap out with Zend_Db_Profiler_Firebug?
UPDATE: See my answer below.
As of ZF 1.11.11 there is no built in profiler class that will log queries to a file. Currently, FireBug is the only specialized Db Profiler.
Here are two ways in which you can solve it without loads of extra code though.
First, check out this answer as it shows how to extend Zend_Db_Profiler to have it log the queries to a file on queryEnd. If it doesn't quite do what you want, you can extend Zend_Db_Profiler and use the provided code as a starting point.
This next example is a slight modification of a plugin I have in some of my applications that I use to profile queries when the application is in development. This method utilizes a dispatchLoopShutdown() plugin to get an instance of the Db Profiler and log the queries to a file.
<?php /* library/My/Page/DbLogger.php */
class My_Page_DbLogger extends Zend_Controller_Plugin_Abstract
{
public function dispatchLoopShutdown()
{
$db = Zend_Controller_Front::getInstance()->getParam('bootstrap')->getResource('db');
$profiler = $db->getProfiler();
if ($profiler === NULL || !($profiler instanceof Zend_Db_Profiler))
return;
// either create your logger here based on config in application.ini
// or create it elsewhere and store it in the registry
$logger = Zend_Registry::get('dblog');
$totalQueries = $profiler->getTotalNumQueries();
$queryTime = $profiler->getTotalElapsedSecs();
$longestTime = 0;
$queries = $profiler->getQueryProfiles();
if ($queries !== false) {
$content = "\nExecuted $totalQueries database queries in $queryTime seconds<br />\n";
foreach ($queries as $query) {
// TODO: You could use custom logic here to log only selected queries
$content .= "Query (" . $query->getElapsedSecs() . "s): " . $query->getQuery() . "\n";
if ($query->getElapsedSecs() > $longestTime) {
$longestTime = $query->getElapsedSecs();
}
}
$content .= "Longest query time: $longestTime.\n" . str_repeat('-', 80);
$logger->info($content);
}
}
}
To activate this plugin, you can use code like this in your bootstrap:
/**
* Register the profiler if we are running in a non-production mode
*/
protected function _initPageProfiler()
{
if (APPLICATION_ENV == 'development') {
$front = Zend_Controller_Front::getInstance();
$front->registerPlugin(new My_Page_DbLogger());
}
}
Ideally, in the long term, you would probably want to make a class that extends Zend_Db_Profiler and allow additional options to be specified in your config such as the log file path, the log priority. This way you can leverage the existing filters to Zend_Db_Profiler.

Categories