CodeIgniter creating multiple custom Form_validation extension classes - php

I know that I can make a file called MY_Form_validation based on the default
$config['subclass_prefix'] = 'MY_';
But what if I have different forms that I want to represented with different MY_Form_validation classes? If this is possible, how will I load and call it in my validation controller?
For example MY_Student_registration_form_validation, MY_Student_cancellation_form_validation, and so on?
Most of the question online just straightforward suggest creating this sole class but not for multiple instances.
NOTE I tried creating MY_Student_registration_form_validation class inside application/libraries (CI 3.x) and loaded it in my controller using
$this->load->library('my_student_registration_form_validation');
and I got the error Non-existent class: My_student_registration_form_validation.
Then I tried without the prefix MY
$this->load->library('student_registration_form_validation');
and I got a different one Unable to load the requested class: Student_registration_form_validation.

Alright kids I got it now.
Create your custom form validation class with the prefix MY_ or whatever you declared in the application/config/config.php file. For example, MY_Student_registration_form_validation inside application/libraries for CI 3.x.
$config['subclass_prefix'] = 'MY_';
In your controller (I will use controller here since I haven't tested it on a model), you can load this custom class by:
$this->load->library('my_student_registration_form_validation');
You can now use its methods by:
$this->my_student_registration_form_validation->validate_student();

Put this piece at the end of APPPATH.'config/config.php' file
spl_autoload_register(function ($class) {
//this block you can skip
if (substr($class,0,3) !== 'CI_') {
if (file_exists($file = APPPATH.'core/'.$class.'.php')) {
include $file;
}
}
//this block is what you need
if (substr($class,0,3) !== 'CI_') {
if (file_exists($file = APPPATH.'libraries/'.$class.'.php')) {
include $file;
}
}
});
This way, you don't even set config file's predefined MY_ prefix.
Name your files and classes like:
Student_registration_form_validation.php | Student_registration_form_validation
Student_cancellation_form_validation.php | Student_cancellation_form_validation
Some_controller_code.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class Some_controller_code extends CI_Controller
{
public function __construct()
{
parent::__construct();
}
public function index()
{
//you have to load form_validation library first
//if custom libraries are extending it
$this->load->library('form_validation');
$this->load->library('student_registration_form_validation');
//example of using method from native form_validation library
if ( $this->student_registration_form_validation->set_message('rule1', "Some message here") )
echo 'It\'s working';
}
}

Related

Where should I require vendor/autoload.php in CodeIgniter?

I want to add some code that will run for every controller. Adding the code to CodeIgniter's CI_CONTROLLER class seems unconventional.
Where is the right place to include code you want to run for every controller?
Here is the code:
require_once 'vendor/autoload.php';
$bugsnag = Bugsnag\Client::make("my-secret-key-is-here");
Bugsnag\Handler::register($bugsnag);
These classes both come from a dependency installed with Composer.
I suspect I should create a helper, and include it in application/config/autoload.php. But new to CodeIgniter, so not sure of conventions.
Edit: I am using CodeIgniter 3.1.6.
If you want to execute arbitrary code at different points in CodeIgniter's life cycle, you can use the hooks feature.
Official Documentation:
https://codeigniter.com/user_guide/general/hooks.html
1. Enable hooks
Go to /application/config/config.php.
Search for enable_hooks and set it to true: $config['enable_hooks'] = TRUE;
2. Add desired code to CodeIgniter's hook file:
Go to /application/config/hooks.php.
Choose the desired lifecycle to hook into (see doc link above for a list)
Add code to the lifecycle, e.g. $hook['pre_controller'] = function(){... your code goes here ...}
For this question's example, my hooks.php looks like this:
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
// This is the code I added:
$hook['pre_system'] = function(){
require_once 'vendor/autoload.php';
$bugsnag = Bugsnag\Client::make("my-client-key");
Bugsnag\Handler::register($bugsnag);
}
?>
I would just extend the Controller Class.
See "Extending Core Class":
"If all you need to do is add some functionality to an existing library - perhaps add a method or two - then it’s overkill to replace the entire library with your version. In this case it’s better to simply extend the class."
...
"Tip: Any functions in your class that are named identically to the methods in the parent class will be used instead of the native ones (this is known as “method overriding”). This allows you to substantially alter the CodeIgniter core."
class MY_Controller extends CI_Controller {
....
}
Any function you put inside would be added to the core, otherwise, if you use the same name as an existing method, it would replace just that one method.
You'd name it MY_Controller.php and put it inside application/core/, where it's picked up to override CI_Controller automatically.
If you are extending the Controller core class, then be sure to extend your new class in your application controller’s constructors.
class Welcome extends MY_Controller {
public function __construct()
{
parent::__construct();
// Your own constructor code
}
public function index()
{
$this->load->view('welcome_message');
}
}
Looks like you could also use a pre_system or pre_controller hook as described here:
https://www.codeigniter.com/user_guide/general/hooks.html
Assuming it's CodeIgnitor 3.X
Go to application/config/config.php and change:
$config['composer_autoload'] = FALSE;
to
$config['composer_autoload'] = TRUE;
just below the above line include
require_once APPPATH.'vendor/autoload.php';
Or in your controller include
require_once APPPATH.'vendor/autoload.php';
From How to use composer packages in codeigniter?
Go to application/config/config.php and set $config['composer_autoload'] = FALSE; to TRUE:
Enabling this setting will tell CodeIgniter to look for a Composer
package auto-loader script in application/vendor/autoload.php.
As a result you need not to call require_once 'vendor/autoload.php';.

Extending and extended class in CodeIgniter 3

I have a controller "MY_Controller.php" in "application/core" that extends "CI_Controller":
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
class MY_Controller extends CI_Controller
{
function __construct()
{
parent::__construct();
$this->load->helper('form');
$this->load->helper('url');
$this->load->helper('security');
$this->load->helper('language');
// Load language file
$this->lang->load('en_admin', 'english');
}
}
I created another controller called "Auth.php" in "application/controllers" that extends "MY_Controller":
class Auth extends MY_Controller
{
function __construct()
{
parent::__construct();
$this->load->library('ion_auth');
if ($this->ion_auth->logged_in() === FALSE) {
redirect('user/login');
}
}
}
I created a third controller "Dashboard.php" that should extend "Auth", but throws an error:
class Dashboard extends Auth
{
public function index()
{
echo 'Hello from the dashboard';
}
}
Fatal error: Class 'Auth' not found in /home/user/www/forum/application/controllers/Dashboard.php on line 5
Would appreciate your advice to solve this problem.
The link in my comment has multiple ways to solve your problem. I prefer to use the #3 method - "Using an autoload function with hooks". Here's what works for me.
application/config/config.php
$config['enable_hooks'] = TRUE;
application/config/hooks.php
$hook['pre_system'][] = array(
'class' => '',
'function' => 'register_autoloader',
'filename' => 'Auto_load.php',
'filepath' => 'hooks'
);
application/hooks/Auto_load.php
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
function register_autoloader()
{
spl_autoload_register('site_autoloader');
}
/*
* Custom autoloader.
* This piece of code will allow controllers and other classes
* that do not start with "CI_" to be loaded when
* extending controllers, models, and libraries.
*/
function site_autoloader($class)
{
if(strpos($class, 'CI_') !== 0)
{
if(file_exists($file = APPPATH.'core/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'libraries/'.$class.'.php'))
{
require_once $file;
}
elseif(file_exists($file = APPPATH.'models/'.$class.'.php'))
{
require_once $file;
}
}
}
Your first extend of CI_Controller - class MY_Controller extends CI_Controller - should probably be in application/core/MY_Controller.php. Any classes that extend MY_Controller should be in application/libraries/.
The linked page labels the "hook" method as "the slow and right way" but the profiling I did comparing it to "2. Using an autoload function (the fast and dirty way)" showed a time difference of slightly over a microsecond. That's not worth worrying about.
I used the "fast and dirty way" for many years but kept forgetting about it when upgrading CI and I'd overwrite the config file resulting in a lost autoloader routine. Don't have that problem using the hook method other than remembering to set $config['enable_hooks'] to TRUE.
This is the regular behavior. Controllers do not extend each other. They may only extend MY_Controller (or CI_Controller). This is true for all MVC frameworks.
The way to use ion_auth, is not to extend Auth controller. You have already loaded ion_auth library, so you may directly use its methods in all controllers, the same way you use them in Auth controller.
Documentation for ion_auth here.
Well I've never used MY_Controller. I specify my class names.
I create all my classes under application/libraries and my structure is
Admin extends Common_Controller
Common_Controller handles the auth stuff for admin and members login/auth etc
Admin is a Controller up in application/modules/admin/controllers/Admin.php
Common_Controller extends Base_Controller
Base_Controller handles all the stuff common to all controllers like the templating etc
Base_Controller extends MX_Controller
MX_Controller is the wiredesignz HMVC Controller
MX_Controller extends CI_Controller
and we are done.
This is of course a HMVC setup but the principle is the same. Just don't use MY_Controller, give it a real name and use it normally.
And of course HMVC uses MY_Loader and other classes MY_xxx it uses to hook itself into CI and they live under application/core and it all plays nicely.
So as far as I can tell, there isn't a limit on how many classes deep you can go when you are extending them.

CodeIgniter creating MY_Controller

How can i create MY_Controller. Where is right place to put this file, i put it in core, folder, and i add into autoload file
code
function __autoload($class)
{
if(strpos($class, 'CI_') !== 0)
{
#include_once( APPPATH . 'core/'. $class . EXT );
}
}
then i created MY_Controller
class My_Controller extends CI_Controller
{
public function __construct() {
parent::__construct();
$this->load->view('view_header');
$this->load->view('includes/nav_home');
$this->load->view('view_home');
$this->load->view('view_footer');
}
}
but i keep getting error
Class 'MY_Controller' not found in C:\wamp\www\vezba\application\controllers\pages.php on line 4
i called MY_Controller in file
class Pages extends MY_Controller
{
function __construct() {
parent::__construct();
}
}
Where could be problem??
Double check the case on your class name and file name.
class MY_Controller extends CI_Controller
Notice how MY_ is all upper-case. Make sure this file is saved as application/core/MY_Controller.php, again note the case.
CodeIgniter should auto-load this file for you.
Docs: https://www.codeigniter.com/user_guide/general/core_classes.html
P.S. Check the $config['subclass_prefix'] option in your application/config/config.php file.
You don't need the autoloading functionality. Codeigniter will automatically load My_Controller as long as it's in your application/core directory.
You don't need to autoload your class, the framework will do it for you. In your case check the config file whether the subclass_prefix is 'MY_'. Eg; $config['subclass_prefix'] = 'MY_';
Put your class in application/core. Make sure the class name and the file name is the same.

CodeIgniter - is it possible to create my own controller in any other name

I have created custom controller called "MY_Controller.php" in Application/core, and successfully invoked by inheriting through application controller.
//application/core
class MY_AdminController extends CI_Controller {
function __construct() {
parent::__construct();
}
}
//application/controllers
class User extends MY_AdminController {
public function __construct(){
parent::__construct();
}
}
It works fine. I just changed my file name from "MY_Controller.php" to MY_AdminController.php, and following same class name, but it is throwing following error,
Fatal error: Class 'MY_AdminController' not found
As per the documentation, Whenever you create a class with the MY_ prefix the CodeIgniter Loader class will load this after loading the core library, then why its throwing error...!!!
Go to your config.php and change
$config['subclass_prefix'] = 'MY_'; to $config['subclass_prefix'] = 'MY_Admin';
Expanding on Patel,
the issue is that MY_ is the prefix to the original core files.
Controller, Model, View etc.
MY_ will be used to seek the name of the controller, for example, MY_controller searches for CI_controller.
You cannot load random names using the MY_prefix. you use MY_ to extend the already existing names.
I think the problem is with the class name, you may have not changed the class name from MY_Controller to MY_AdminController
You can use custom classes. But CI only loads the classes with the class prefix in the config file (e.g. MY_). So I explained how it works and created a workaround to load classes automatically. You can find it here https://stackoverflow.com/a/22125436/567854.
Hope this helps :)
If you want to include all the files that are in your core folder. Then write the following code in end of config.php file.Path to file is application/config/config.php
function __autoload($class)
{
if (strpos($class, 'CI_') !== 0)
{
#include_once( APPPATH . 'core/' . $class . EXT );
}
}
By using this you can create multiple classes.

Extending CI_Controller

All I'm trying to do is something fairly simple :
Create a class (let's say brandNewClass - NOT MY_Controller) which extends CI_Controller
Create other controllers which extend brandNewClass
E.g.
class brandNewClass extends CI_Controller {
public function index()
{
}
public function info()
{
}
}
used like (in a file under /controllers) :
<?php
class newController extends brandNewClass
{
}
?>
The thing is, although it works when I'm copying the file under /application/core and naming it as MY_Controller, when I change the name to something more... self-explanatory, it doesn't.
Fatal error: Class 'brandNewClass' not found in .... on line ..
I've even tried using the __autoload function mentioned here, but without any luck.
Any ideas?
Have a look at this excellent tutorial - I hope it helps
http://codeigniter.tv/a-10/Extending-the-core-MY_Controller-and-beyond
The autoloader doesn't automaticly include other controllers. you will have to include it manually like this:
if (!defined('BASEPATH'))exit('No direct script access allowed');
include_once(APPPATH . 'controllers/brandnewclass.php');
If you want to create a custom base controller and make other controllers extend there, you can do it in following ways:
Create MY_Controller extending CI_Controller in application/core/ folder and make other controllers extend MY_Controller as MY_Controller will be autoloaded from core (This I guess you already know but want other alternatives.
Create MY_Controller in application/core/. Then create other level of Controllers that can primarily be Admin_Controller and Frontend_Controller. Now, one of these controllers will make base for your actual used controllers.
e.g. in application/core/MY_Controller.php
class MY_Controller extends CI_Controller {
public function __construct(){
parent::__construct();
}
}
Then Admin and Frontend controllers will be created in application/libraries/ and will extend MY_Controller like
class Admin_Controller extends MY_Controller {
public function __construct(){
parent::__construct();
}
}
Now, Any controller can extend one of these 2 controllers but for doing that you will have to autoload them. For autoloading in this case there can be a confusion because setting autoload['libraries'] in config/autoload.php will not work . That autoload works inside a controller but here we need to autoload before that i.e. in the class declaration. Will need to set this code in config/config.php
function __autoload($class)
{
$path = array('libraries');
if(strpos($class, 'CI_') !== 0) {
foreach($path as $dir) {
$file = APPPATH.$dir.'/'.strtolower($class).'.php';
if (file_exists($file) && is_file($file))
#include_once($file);
}
}
}
Now you can create your own controller
class newController extends Admin_Controller
{
}
This is the most suggested method making your structure quite clean and effective. May take some effort in understanding for the first time but is definitely worth it.
Third method is just a tweak of the second one, just based on the condition you mentioned of not using MY_Controller
You can make Admin_Controller or Frontend_Controller extend CI_Controller directly and not extend MY_Controller
That may just lead to some duplicity of code in both these controllers if that may be the case
http://philsturgeon.co.uk/blog/2010/02/CodeIgniter-base-Classes-Keeping-it-DRY
I suspect you're trying something similar?
There's an autoload function that you can add to the config file so that you needen't require_once() the class all the time.
You should declare the class as abstract, since it shouldn't be instantiated directly.
You'll need to modify the CodeIgniter autoloader configuration file and add your class to it, or change the actual autoloader.
You really should consider not using CodeIgniter :)

Categories