Trait in CodeIgniter - php

I'm trying to use traits in CodeIgniter. I put the Trait in the libraries directory and then loaded the library in the controller. Then I used the trait in the model, but it didn't work and I received the following error
Trait file (in library):
trait DataTablesTrait{
public function query(){
$this->db->select('*');
$this->db->limit(10, 1);
return $this->db->get('my_table');
}
}
?>
Controller:
class myController extends CI_Controller {
public function __construct(){
parent::__construct();
$this->load->library('DataTablesTrait');
$this->load->model('ABC_Model');
}
}
Model:
class ABC_Model extends CI_Model {
use DataTablesTrait;
function callQuery(){
$this->query();
}
}
I got this error:
Non-existent class: DataTablesTrait
Please advise

CodeIgniter (CI) isn't trait or namespace friendly but they can be used. It requires working around CI a bit though.
The main problem, the CI thing you have to work around, is the call
$this->load->library('DataTablesTrait');
CI will find this file but load->library will try to instantiate the trait which fails because it is not possible to instantiate a Trait on its own.
Replace the line above with
include APPPATH.'/libraries/DataTablesTrait.php';
You should be free of the error with that. But you're not going to get results because callQuery() does not return anything. To round out the test have callQuery() return the CI_DB_result object the Trait should produce
public function callQuery()
{
return $this->query();
}
Add an index function to the controller so we can dump the output
public function index()
{
$DB_result = $this->ABC_Model->callQuery();
var_dump($DB_result->result());
}
This should produce the expected output - assuming that 'my_table' has data :)

Worth saying that traits are now fully supported in Codeigniter 4 and can be implemented as you would expect using namespaces etc.
// TRAIT
namespace App\Controllers\traits;
trait YourTraitName {
}
// CONTROLLER
use App\Controllers\traits\YourTraitName;
class Admin extends BaseController {
use YourTraitName;

Related

How to call a trait method with alias

I'm trying to place a trait inside a class called Page. I also need to rename a trait function so that it doesn't clash with an existing class function. I thought I did all this successfully however I get an error that points to the wrong location?!
Call to undefined function App\Pages\Models\myTraitDefaultScope()
I've also tried: MyTrait\defaultScope($query) instead of trying to rename the conflicting function. But I then get the following error:
Call to undefined function App\MyTrait\defaultScope()
Below is the trait and class contained in separate files.
<?php
namespace App;
use Illuminate\Support\Facades\Auth;
trait MyTrait{
public function defaultScope($query){
return $query->where('active', '1')
}
}
.
<?php namespace Modules\Pages\Models;
use Illuminate\Database\Eloquent\Model;
use App\MyTrait;
class Page extends Model {
use MyTrait{
MyTrait::defaultScope as myTraitDefaultScope;
}
public function defaultScope($query){
return myTraitDefaultScope($query);
}
}
I'm not all that awesome at this so please don't shoot if I've got something badly wrong :)
When you 'use' a trait in your class, the class inherits all the methods and properties of the trait, like if it was extending an abstract class or an interface
So, this method of MyTrait:
public function defaultScope($query){
return $query->where('active', '1')
}
will be inherited by your Page class
As you have aliased this method as: myTraitDefaultScope, to call the method you should call it in the same way you would call every other method of the Page class:
public function defaultScope($query){
//call the method of the class
return $this->myTraitDefaultScope($query);
}
As you're using trait. So it points to the current or parent class. Thus, calling any method should be like $this->method($params); syntax.

How to access class members in traits (or get a similar behaviour)?

This is a follow-up to my previous question about resolving the diamond issue in php.
As I state in that question, I resolve my problem by using traits and passing the instance of the class to the method of the trait. Such as:
trait SecurityTrait
{
public function beforeExecuteRouteTrait($controller, Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
return $this->beforeExecuteRouteTrait($this, $dispatcher);
}
}
However, I am still uncomfortable with this as I don't think this is how traits are really supposed to be used. In my reading I haven't found any way in which to access class members in traits (make $this inside a trait refer to the class using it). Is this possible? Or is there another way to implement a similar behaviour?
After reading some of the answers...
Previously I thought I had received errors when using $this->... inside the trait and this led me to believe the trait could not access anything to do with the underlying class. After reading the answers I tried altering my code to use $this->... inside a trait again and it works - which means a typo several weeks ago has given me far too much headache...
The example given previously now looks like this
trait SecurityTrait
{
public function beforeExecuteRoute(Dispatcher $dispatcher)
{
// Do something that makes use of methods/members of the controller
}
}
class AppController extends Controller
{
use SecurityTrait;
}
Much cleaner and more easily understandable but provides the same functionality.
If you use a trait inside a class then that trait has full access to all class's members and vice versa - you can call private trait methods from the class itself.
Think of traits as code that literally gets copy/pasted into the class body.
For example:
trait Helper
{
public function getName()
{
return $this->name;
}
private function getClassName()
{
return get_class($this);
}
}
class Example
{
use Helper;
private $name = 'example';
public function callPrivateMethod()
{
// call a private method on a trait
return $this->getClassName();
}
}
$e = new Example();
print $e->getName(); // results in "example"
print $e->callPrivateMethod(); // results in "Example"
In my view referencing classes in traits is not the best way to use them but there's nothing stopping anyone from doing it.
No, that's exactly what Traits are for. Your class already extends a class so you can't inherit the methods and variables of any other classes.
Think of a Trait like copy/paste for code execution. When a class includes a Trait, it's just as if you had written all that code into the class itself.

how to return error_array(); in codeigniter 2.2.1

trying to return form_validation as an array using _error_array(); by extending the library with the following code in my_form_validation.php
class MY_Form_validation extends CI_Form_validation {
public function error_array() {
return $this->_error_array;
}
}
however i get a call to undefined function n error_array();
in my controller i have $this->form_validation->error_array();
i have tried renaming the my_form_validation.php with MY_Form_validation.php
but nothing seems to be working dont know if its done diffrently in codeigniter 2.2.1 compared to other posts on here
'Nothing seems to be working' doesn't help if there is no explanation what is going on on your screen/in yoour application.
Regardless, you have to include constructor in your newly created library that calls parent code.
class MY_Form_validation extends CI_Form_validation
{
public function __construct()
{
parent::__construct();
}
public function error_array()
{
return $this->_error_array;
}
}
Also, you would load that library without prefix:
$this->load->library('form_validation');
or similarly in autoload.php app config file.
More about Extending Native Libraries.

Inheriting constructors php 5.2.6

I have a relatively simple question. I am trying to inherit a constructor from a php superclass to authenticate on this controller.
Here is my super class:
class Auth_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
if(!session_id()){
session_start();
}
$this->load->view('login_v/logincheck');
}
}
and here is my subclass:
class Event_Controller extends Auth_Controller {
function __construct()
{
parent::__construct();
}
public function get_events_by_owner() {
$this->load->model('Event_model');
$data['events'] = $this->Event_model->select_by_owner($_SESSION['SignedIn']);
$this->load->view('event_view', $data);
}
}
This is not working. only a white page is rendered. I'm not sure why it isn't working. If I move the constructor from Auth_Controller to Event_Model this works.
Thanks!
EDIT:
Fatal error: Class 'Auth_Controller' not found in
../controllers/event_controller.php on line 12
Your solution is not going to work, you should try either:
Move this code:
if(!session_id()){
session_start();
}
$this->load->view('login_v/logincheck');
to a cutom library, than run this library within constructor of your controller. Please read Creating Libraries for details.
or:
Create MY_Controller class and put auth code (quoted above) into its constructor. Than you'll be able to extend like:
class Event_Controller extends MY_Controller {
(...)
Please read Creating Core System Classes for details.

Calling member function of other controller in zend framework?

Is it possible to call the member function of another controller in zend framework, if yes then how?
<?php
class FirstController extends Zend_Controller_Action {
public function indexAction() {
// general action
}
public function memberFunction() {
// a resuable function
}
}
Here's another controller
<?php
class SecondController extends Zend_Controller_Action {
public indexAction() {
// here i need to call memberFunction() of FirstController
}
}
Please explain how i can access memberFunction() from second controller.
Solution
Better idea is to define a AppController and make all usual controllers to extend AppController which further extends Zend_Controller_Action.
class AppController extends Zend_Controller_Action {
public function memberFunction() {
// a resuable function
}
}
class FirstController extends AppController {
public function indexAction() {
// call function from any child class
$this->memberFunction();
}
}
Now memberFunction can be invoked from controllers extending AppController as a rule of simple inheritance.
Controllers aren't designed to be used in that way. If you want to execute an action of the other controller after your current controller, use the _forward() method:
// Invokes SecondController::otherActionAction() after the current action has been finished.
$this->_forward('other-action', 'second');
Note that this only works for action methods (“memberAction”), not arbitrary member functions!
If SecondController::memberFunction() does something that is needed across multiple controllers, put that code in a action helper or library class, so that both controllers can access the shared functionality without having to depend on each other.
You should consider factoring out the code into either an action helper or to your model so that it can be called from both controllers that need it.
Regards,
Rob...
I would suggest you to follow DRY and move those functions to common library place. For example create in library folder
My/Util/
and file
CommonFunctions.php
then call your class
My_Util_CommonFunctions
and define your methods
Now you can call them from any place in the code using your new namespace which you have to register.
$loader = Zend_Loader_Autoloader::getInstance();
$loader->registerNamespace(array('My_'));
in any controller you can call your custom methods by using:
My_Util_CustomFunctions::yourCustomMethod($params);

Categories