I'm trying to extend the CodeIgniter Form Validation library - php

This is my custom validation function. It uses geocoding from a Google Maps CodeIgniter library to check if a location exists.
public function address_check($str)
{
$this->load->library('GMap');
$this->gmap->GoogleMapAPI();
// this method checks the cache and returns the cached response if available
$geocodes = $this->gmap->getGeoCode("{$str}, United States");
$this->form_validation->set_message('address_check', 'The %s field contains an invalid address');
if (empty($geocodes))
{
return FALSE;
}
else
{
return TRUE;
}
}
If I place the function above inside my Controller along with the following rule, it works perfectly well.
$this->load->library('form_validation');
$this->form_validation->set_rules('location', 'Location', 'callback_address_check');
Now I simply want to move it out of my Controller. So I'm trying to extend my CodeIgniter Form Validation library as per this SO answer and the CI documentation.
I created a file here: /codeigniter/application/libraries/MY_Form_validation.php:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class MY_Form_validation extends CI_Form_validation {
public function __construct()
{
parent::__construct();
}
public function address_check($str)
{
$this->load->library('GMap');
$this->gmap->GoogleMapAPI();
// this method checks the cache and returns the cached response if available
$geocodes = $this->gmap->getGeoCode("{$str}, United States");
$this->form_validation->set_message('address_check', 'The %s field contains an invalid address');
if (empty($geocodes))
{
return FALSE;
}
else
{
return TRUE;
}
}
}
And from within my controller, I am setting the rule like this...
$this->load->library('form_validation');
$this->form_validation->set_rules('location', 'Location', 'address_check');
The first problem I found and solved myself was that nothing was happening because that SO answer incorrectly specified the file name to be My_Form_validation.php where it should have been MY_Form_validation.php
Now that the function is being called, the new problem is that I am getting the following error:
Message: Undefined property: MY_Form_validation::$load
Filename: libraries/MY_Form_validation.php
Line Number: 12
This is line 12:
$this->load->library('GMap');
I can't access a library from within a library? What's the proper way to fix this? I'd prefer not to auto-load the GMap library since I won't be using it all the time. Any other problems within my method?

Use this:
$CI =& get_instance();
$CI->load->library('GMap');
And then use it like:
$CI->gmap->GoogleMapAPI();
You have to do it that way, because Form Validation is not like CI Model or Controller class, it's only library.

Inside of your library, you can extend other models, libraries, configs, helpers, etc... by first loading the CI class. For example, in your constructor you can accomplish this through the following:
public function __construct()
{
parent::__construct();
$this->ci =& get_instance();
}
Once you have loaded the CI class, you can load any other classes that may need loading.
Examples:
$this->ci->load->library("session");
$this->ci->load->model("my_model");
$this->ci->load->helper("file");
Or in your case:
$this->ci->load->library("GMap");
You can then call functions from the class in a similar fashion throughout your class:
$this->ci->gmap->GoogleMapAPI();
$this->ci->gmap->getGeoCode("{$str}, United States");

Related

Codeigniter - Can only load model in autoload.php

I'm going crazy because I have been using Codeigniter for ages now and I cannot seem to load a model in my view.
This is what I have done. Model code (models/changelog.php):
<?php
class Changelog extends CI_Model {
function __construct() {
parent::__construct();
$this->load->database();
}
function get_list() {
$query = $this->db->get('changelog');
return $query->result();
}
}
/* Location: ./application/models/changelog.php */
This is my controller (controllers/explore.php):
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Explore extends CI_Controller {
public function index() {
$this->load->view('include/header');
$this->load->view('home');
$this->load->view('include/footer');
}
public function changelog() {
$this->load->model('changelog');
$data['changelog_row'] = $this->changelog->get_list();
$this->load->view('include/header');
$this->load->view('explore/changelog', $data);
$this->load->view('include/footer');
}
}
/* Location: ./application/controllers/explore.php */
I get a Codeigniter notice telling me Message: Undefined property: Explore::$Changelog and a PHP error, Fatal error: Call to a member function get_list() on a non-object.
Here is what I did
Tried to autoload the database instead of only loading it in that model
Tried changing the Changelog call in the contorller to lowercase
Checked the connection to the database
Enabled the log file, which doesn't tells me anything new
Everything works correctly, maybe it's just me being a little tired, but if someone could help me out i'd love that :)
After some tests I found out the error is in the
$data['changelog_row'] = $this->Changelog->get_list();
line of my code. I have no idea what the problem is. Case sensitivity is fine (also tried many combinations of lowercase/uppercase), and even if I create another function with different name (e.g. foo()) with a normal echo inside I get the SAME error but referring to that function.
Here is a screen
Something incredible happened: if I add the 'changelog' model in the autoload.php, it seems it can actually load it. What is going on? I used this code already in many applications without a problem.
Another test I did: if I write
public function __construct() {
parent:: __construct();
$this->load->model('changelog');
}
In the controller or just add parent:: __construct(); in the changelog function like
public function changelog() {
parent:: __construct();
$this->load->model('changelog');
$data['changelog_data'] = $this->changelog->get_list();
$this->load->view('include/header');
$this->load->view('explore/changelog', $data);
$this->load->view('include/footer');
}
It works O_o. But why? I changed the topic title, now everything is around my inability to load my model in the controller's functions.
CI is acting a bit strange with that.
Om unix systems (where filenames a case sensitive) you have to load the model with case senstive names.
However in the controller you should address it with lowercase, i.e
$this->load->model('changeLog');
$this->changelog->getList();
Please change your changelog function with following syntax.
public function changelog() {
$this->load->model('changelog', 'model');
$data['changelog_row'] = $this->model->get_list();
$this->load->view('include/header');
$this->load->view('explore/changelog', $data);
$this->load->view('include/footer');
}
And your model's function should be as follows:
public function get_list() {
$query = $this->db->get('changelog');
return $query->result();
}
You miss the public keyword. So, it is a private function now that's why you can't access it from another class.
You are using the same name for the model as for the controller function so getting name clash because;
$this->changelog()
Is trying to refer to the model you have loaded and the class method at the same time.
Rename your Explore::changelog() function (or model name - suffix _m for example) and should be fine. Something like;
$this->changelog_m->getList();
After many hours of test and messing up with everything, INCLUDING configuration files... I DID IT!
It was something totally above models and controllers, it was something about the hooks I called. In fact, I have a hook called languageloader.php written like this:
class LanguageLoader extends CI_Controller {
public function initialize() {
$ci =& get_instance();
$site_lang = $ci->session->userdata('site_lang');
if (!empty($site_lang)) {
$ci->lang->load('text', $site_lang);
} else {
$ci->lang->load('text', 'english');
}
}
}
In my hooks file it was loaded like:
$hook['post_controller_constructor'] = array(
'class' => 'LanguageLoader',
'function' => 'initialize',
'filename' => 'languageloader.php',
'filepath' => 'hooks',
);
Since I was using post_controller_constructor, referring to CI doc files it is
Called immediately after your controller is instantiated, but prior to
any method calls happening.
I believe that doing something like my $ci =& get_instance(); I couldn't instance my damn model. I fixed it by changing the hook to
$hook['pre_controller']
I didn't think it could have been something about the hooks and that was the reasons why I didn't post it. Thanks to everyone who tried to help me out in the while. I hope this helped someone else who was in my same trouble!
For your reference, you can modify your autoload.php from
./application/config/autoload.php
then just include all you models exist on your model folder
./application/models/*_Model.php
So from autoload.php set your autoload['model'] array.
/*
| -------------------------------------------------------------------
| Auto-load Models
| -------------------------------------------------------------------
| Prototype:
|
| $autoload['model'] = array('first_model', 'second_model');
|
| You can also supply an alternative model name to be assigned
| in the controller:
|
| $autoload['model'] = array('first_model' => 'first');
*/
$autoload['model'] = array('Foo_Model', 'Bar_Model', ...);
Then from your Controller you can remove the $this->load(...); from your __construct(), since all Models you defined from autoload.php is loaded Globally and can be use whenever you run your system.
Then just call directly the public methods you need from that Model, like so;
$this->Foo_Model->your_public_method_to_call();
PS:
CI_VERSION: 3.x
PHP: 5.4+
I hope this helps somebody, thanks.

CodeIgniter adding page doesn't work

I have taken over a project written in CodeIgniter, which I have never used before. I have added a new file to views/pages called features.php, and have read on the internet that to make it accessible, I need to create a function in the controller file that will render the page.
I have tried the following:
public function features()
{
$this->render('template', 'pages/features');
}
However, when I try to open features.php, it gives me 404. How can I fix that?
Update 1 - Class
Here is the controller's class code:
class Pages extends MY_Controller {
function __construct()
{
parent::__construct();
$this->load->model('setting_model', 'setting');
$this->load->model('order_model', 'order');
$this->load->model('page_model', 'page');
$this->load->library('form_validation');
$this->load->helper(array('inflector', 'string'));
}
public function index()
{
$settings = $this->setting->get_settings();
$data['document_price'] = $settings->document_price;
$this->render('template', 'pages/index', $data);
}
//This works fine
public function about_us()
{
$this->render('template', 'pages/about_us');
}
//Here is the problem, although it follows the same pattern as about_us()
public function features()
{
$this->render('template', 'pages/features');
}
}
As you are using $this->render I guess you are using the template library. I think you should be using:
public function features()
{
$this->template->set_template('template');
$this->template->write_view('pages/features');
$this->template->render();
}
The php files contained in /views are not directly accessible by typing in some URL. CodeIgniter is an MVC framework. That means that your URLs are mapped to your controllers and the controllers call the views.
What is the name of the class that this function is encapsulated in? Please post the entire class and not just the features() function and we can help you out. If you're working locally, the default mapping to call controllers is: http://localhost/appname/controller/function/param1/param2/etc.
The $this->render() function is not vanilla CodeIgniter syntax, you either inherited a project that is using a templating library, or, there is a sibling render() function inside the controller class.
Check your config/routes.php file as well and consider posting it.
If you want to diagnose the issue, try pinpointing by removing the call to $this->render() and instead using CodeIgniter's native $this->load->view('pages/features') function. If this works, we can be sure it's the library or render() call.

Library not being extended in codeigniter

So I'm trying to extend the input library (CI 2.1.1), and when I call my custom save query function, its saying the function doesn't exist.
File: MY_Input.php, in the applications/libraries folder:_
class MY_Input extends CI_Input {
var $CI;
function __construct() {
parent::__construct();
$this->CI =& get_instance();
}
function save_query($query_array) {
$this->CI->db->insert('ci_query', array('query_string' => http_build_query($query_array)));
}
}
And in the controller I'm calling the function like this
$query_id = $this->input->save_query($query_array);
So what on earth am I doing wrong that it's giving me this error:_
Fatal error: Call to undefined method CI_Input::save_query() in ....
Can't see why it's not working, I even checked the user guide and according to it I guess I'm doing it right. :/
The CI_Input class is a core library (new thing in CI2.0.0). You will have to put your MY_Input.php file under application/core/ to make the framework pick it up.
When in doubt, look for the original class under system/core or system/libraries and mirror it under application/.

How can I use session in a library in CodeIgniter?

I want to check if user is logged in CodeIgniter by using my library in the controller's constructor.
This is my library:
class Administrator_libs {
public function validate_authen(){
if( $this->session->userdata('user_authen') ){
redirect(base_url().'admin/login/');
}
}
}
And this is my controller:
class Administrator extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->library('administrator_libs');
$this->administrator_libs->validate_authen();
$this->load->model('mod_menu');
}
}
But I get this error message:
Undefined property: Administrator_libs::$session
How can I use session in a library in CodeIgniter?
If you want to access any CodeIgniter library inside of your own, you must call get_instance(). This is because $this is bound to your current library and not the CodeIgniter object.
$CI =& get_instance();
if( $CI->session->userdata('user_authen') ){
redirect(base_url().'admin/login/');
}
Please see Creating Libraries CodeIgniter Documentation. Specifically the content under Utilizing CodeIgniter Resources within Your Library
This assumes you autoload the session library in config/autoload.php, if not, you'll also need to add $CI->load->library("session"); after $CI instantiation.
IMPORTANT: =& is not a typo. It's passed by reference to save memory.
You should simply go to application/autoload.php and add your autoload package which should look like somewhat like this : $autoload['packages'] = array('database','form_validation','session','email');
you can see there is session package that i added in my packages. Now coming to your constructor you should load this package by adding this : $this->load->library("session");
Session and any other lib / helper , etc extends from CI_Controller / CI_Model / etc...
If you are trying to use $this->whatever on a library that doesn't extends from any of this CI modules, you'll get the error.
As Jordan says, you can use get_instance.

Why are two controller methods being called in CodeIgniter?

Should I not be using Index as the name for a controller class in CodeIgniter? I have an Index controller, and I'm seeing its methods being called multiple times. More specifically, I always see its index method called first, whether or not I'm visiting a path that should be routed there.
In application/controllers/index.php
class Index extends CI_Controller
{
public function index()
{
echo "index";
}
public function blah()
{
echo "blah";
}
}
When I visit index/blah, I see indexblah printed. When I visit index/index, I see indexindex. If I rename the controller to something else (e.g. Foo), it doesn't have a problem. That's the obvious workaround, but can anyone tell me why this is happening? Should I report this as a bug to CodeIgniter?
(Notes: I have no routes set up in configs/routes.php; my index.php is outside the CodeIgniter tree)
To further clarify what the issue is, in PHP4 Constructors were a function that had the same name as the Class...
example
class MyClass
{
public function MyClass()
{
// as a constructor, this function is called every
// time a new "MyClass" object is created
}
}
Now for the PHP5 version (Which codeigniter now, as of 2.0.x, holds as a system requirement)
class MyClass
{
public function __construct()
{
// as a constructor, this function is called every
// time a new "MyClass" object is created
}
}
So To answer the question that addresses the problem...
Should I not be using Index as the name for a controller class in CodeIgniter?
I believe it would be best to not choose Index as a controller name as the index() function has a reserved use in codeigniter. This could cause issues depending on your PHP configuration.
can anyone tell me why this is happening?
When your controller get's instantiated, index as the constructor is getting called.
Compare Constructors and DestructorsDocs:
For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class . [highlighting by me]
In your case your Controller does not have any __construct() function but a function that has the same name as the class: index. It is getting called in the moment Codeigniter resolves and loads and then instantiates your Index Controller.
You can solve this by just adding the constructor to your Controller:
class Index extends CI_Controller
{
public function __construct() {}
public function index()
{
echo "index";
}
public function blah()
{
echo "blah";
}
}
After this change, it does not happen again.
Should I report this as a bug to CodeIgniter?
No, there is not really a need to report this as a bug, it's how the language work and as Codeigniter supports PHP 4 it must remain backwards compatible and needs to offer PHP 4 constructors. (Note: The Codeigniter project documents, they need server support for PHP version 5.1.6 or newer, but the actual code has PHP 4 compatiblity build in, I'm referring to the codebase here, not the documentation.)
Here is another solution using Codeigniter3
require_once 'Base.php';
class Index extends Base
{
public function __construct()
{
parent::index();
$classname=$this->router->fetch_class();
$actioname=$this->router->fetch_method();
if($actioname=='index' || $actioname == '')
{
$this->viewall();
}
}
}
And the viewall() had the following
$this->siteinfo['site_title'].=' | Welcome';
$this->load->view('templates/header', $this->siteinfo);
$this->load->view('templates/menu', $this->siteinfo);
$this->load->view('index/viewall', $data);
$this->load->view('templates/footer', $this->siteinfo);
The Base controller does all the library and helper loading for the entire application which is why it is being required in the default class
Basically from my short understanding of CodeIgniter, having a default action as index is a wrong. I found this out by using the printing the result of $this->router->fetch_method(); in the construct() of my index class. The default action by CodeIgniter is index, you may only set the default controller within application/config/routes.php and not the default action.
So my advice, never use index() as the default action especially if you are using index as the default controller

Categories