I am new to PHP OOP and CodeIgniter and I need help. I am using CodeIgniter 4 and trying to preload model logas_model in BaseController.php:
<?php
namespace App\Controllers;
/**
* Class BaseController
*
* BaseController provides a convenient place for loading components
* and performing functions that are needed by all your controllers.
* Extend this class in any new controllers:
* class Home extends BaseController
*
* For security be sure to declare any new methods as protected or private.
*
* #package CodeIgniter
*/
use App\Models\Admin\logas_model;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
class BaseController extends Controller
{
/**
* An array of helpers to be loaded automatically upon
* class instantiation. These helpers will be available
* to all other controllers that extend BaseController.
*
* #var array
*/
protected $helpers = ['form', 'session', 'html', 'number'];
protected $logas;
/**
* Constructor.
*/
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
//--------------------------------------------------------------------
// Preload any models, libraries, etc, here.
//--------------------------------------------------------------------
///$this->session = \Config\Services::session();
$this->logas = new logas_model();
}
}
Model logas_model code:
<?php namespace App\Models\Admin;
use CodeIgniter\Model;
use Config\Services;
class logas_model extends Model
{
protected $table = 'veiksmai_logs';
protected $primaryKey = 'id';
protected $returnType = 'array';
protected $useSoftDeletes = true;
protected $useTimestamps = TRUE;
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
protected $deletedField = 'deleted_at';
protected $allowedFields = ['uid', 'veiksmas'];
public function get_all_veiksmai()
{
return $this->select("CONCAT(`user`.`vardas`, ' ', `user`.`pavarde`) AS `user_vardas_pavarde`, `veiksmai_logs`.`veiksmas`, `veiksmai_logs`.`created_at`, `veiksmai_logs`.`id`")
->join('user', 'user.id = veiksmai_logs.uid')
->orderBy("`veiksmai_logs`.`created_at`", 'DESC')
->findAll();
}
public function add_veiksmas($veiksmas)
{
$session = Services::session()->get();
$data = [
'uid' => $session['uid'],
'veiksmas' => $veiksmas
];
return $this->insert($data);
}
}
And then, in other controller, which extends Controller, I am trying to use that preloaded model by using it's function like this:
$this->logas->add_veiksmas('Created User.');
Full that Controller code:
<?php namespace App\Controllers\Admin;
use App\Models\Admin\vartotojai_model;
use CodeIgniter\Controller;
class Vartotojai extends Controller
{
private $vartotojai;
public function __construct()
{
$this->vartotojai = new vartotojai_model();
}
public function index()
{
$this->logas->add_veiksmas('Created User.');
$this->data['vartotojai'] = $this->vartotojai->get_all_vartotojai();
echo view('templates/Admin/Header', ['title' => 'Vartotojai']);
echo view('Admin/Vartotojai/Index', $this->data);
echo view('templates/Admin/Footer');
}
}
But it is not working.
What am I doing wrong?
Change Controller
class Vartotojai extends Controller
{
into BaseController
class Vartotojai extends BaseController
That may be because you have not extended BaseController to Vartotojai controller.
class Vartotojai extends BaseController
Please try this.
Kindly note: whenever you are preloading(Models, helpers, libraries e.t.c), you need to extend the BaseController on all the controllers that will be using that model.In your case you preloaded the model correctly but you did not extend your controller to the BaseController. Use the below format in your controllers:
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
class ClassName extends BaseController
{
//your functions and code
}
?>
Related
I cannot find the problem using
$routes->resource
Please help me figure out what is the problem.
This is how I put my routes resource in config routes :
$routes->resource('ApiManageBanner', ['controller' =>'App\Controllers\ApiData\ApiManageBanner']); // get, put, create, delete
Recently I just move all my project to the newest codeigniter 4 version 4.2.6 from the previous version 4.1.2
This is my controllers :
<?php
namespace App\Controllers\ApiData;
use App\Controllers\BaseController;
use CodeIgniter\RESTful\ResourceController;
use Codeigniter\API\ResponseTrait;
class ApiManageBanner extends ResourceController
{
use ResponseTrait;
function __construct()
{
}
// equal to get
public function index() {
echo "Test";
}
// equal to post
public function create() {
}
// equal to get
public function show($id = null) {
}
// equal to put
public function update($id = null) {
}
// equal to delete
public function delete($id = null) {
}
}
I just try a simple to echo "Test".
But I got this error :
I search everywhere but cannot find the problem related to the error.
If I change the routes name to 'ApiManageBanners' using 's' :
$routes->resource('ApiManageBanners', ['controller' =>'App\Controllers\ApiData\ApiManageBanner']); // get, put, create, delete
It is working.
But I cannot change my routes name because my application is reading
'ApiManageBanner' not 'ApiManageBanners'
I am very curious what cause the problem. It is not working for almost all my resources api controller routes.
I found the problem. According to the error it is related to session. When I check all my file. I found that I always init the :
$this->Session = \Config\Services::session();
In all my controller and model __construct();
function __construct()
{
$this->Session = \Config\Services::session();
}
So I remove it and init globaly in BaseController.php
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use CodeIgniter\HTTP\CLIRequest;
use CodeIgniter\HTTP\IncomingRequest;
use CodeIgniter\HTTP\RequestInterface;
use CodeIgniter\HTTP\ResponseInterface;
use Psr\Log\LoggerInterface;
/**
* Class BaseController
*
* BaseController provides a convenient place for loading components
* and performing functions that are needed by all your controllers.
* Extend this class in any new controllers:
* class Home extends BaseController
*
* For security be sure to declare any new methods as protected or private.
*/
abstract class BaseController extends Controller
{
/**
* Instance of the main Request object.
*
* #var CLIRequest|IncomingRequest
*/
protected $request;
/**
* An array of helpers to be loaded automatically upon
* class instantiation. These helpers will be available
* to all other controllers that extend BaseController.
*
* #var array
*/
protected $helpers = [''];
/**
* Constructor.
*/
public function initController(RequestInterface $request, ResponseInterface $response, LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
// Preload any models, libraries, etc, here.
// E.g.: $this->session = \Config\Services::session();
$this->session = \Config\Services::session();
$this->language = \Config\Services::language();
$this->language->setLocale($this->session->lang);
}
}
Then the error is gone.
How can access properties of a protected object PHP while writing tests. Below is my sample code.
TestCase.php The test fails to run saying that the property is protected. But it can die dumped.
<?php
namespace Tests;
use Illuminate\Http\Response;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
public function getAuthUser()
{
$payload = [
'email' => 'admin#gamil.nl',
'password' => 'password',
];
return $this->json('post', 'api/v1/auth/login', $payload)
->assertStatus(Response::HTTP_OK);
}
}
my sample test
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Http\Response;
class PatientsControllerTest extends TestCase
{
/**
* A basic unit test patient controller.
*
* #return void
*/
public function testPatientFetch()
{
$auth_user = $this->getAuthUser();
dd($auth_user->data);
}
}
my sample code
<?php
namespace Tests\Unit;
use Tests\TestCase;
use Illuminate\Http\Response;
class PatientsControllerTest extends TestCase
{
/**
* A basic unit test patient controller.
*
* #return void
*/
public function testPatientFetch()
{
$auth_user = $this->getAuthUser();
dd($auth_user->data);
}
}
Error received
FAIL Tests\Unit\PatientsControllerTest
⨯ patient fetch
---
• Tests\Unit\PatientsControllerTest > patient fetch
PHPUnit\Framework\ExceptionWrapper
Cannot access protected property Illuminate\Http\JsonResponse::$data
at vendor/phpunit/phpunit/phpunit:98
94▕ unset($options);
95▕
96▕ require PHPUNIT_COMPOSER_INSTALL;
97▕
➜ 98▕ PHPUnit\TextUI\Command::main();
99▕
Tests: 1 failed
Time: 1.05s
You can access and manipulate protected variables with ReflectionClass.
Please try this:
$user = $this->getAuthUser();
$reflectionClass = new ReflectionClass($user);
//If we assume we have a protected variable $data we can get access it with Reflection Class
$property = $reflectionClass->getProperty('data');
$property->setAccessible(true); //Here we are making protected variables accessible
$property->setValue($user, 'New Protected Data');
create getter function for $data
public function get_data(){
return $this->data;
}
unit test to test functions and not properties
I am working with the latest version of codeigniter framework. Something is wrong with my code, it gives me an error like:
Class 'App\Model\Users' not found
Controller
Filename: Auth.php
<?php
namespace App\Controllers;
use CodeIgniter\RESTful\ResourceController;
use App\Model\Users as CodeIgniterUsers;
class Auth extends ResourceController
{
public function login()
{
$model = new CodeIgniterUsers();
var_dump($model);
}
public function register()
{ }
}
Model
File name: Users.php
<?php
namespace App\Model;
use CodeIgniter\Model;
class Users extends Model
{
protected $db;
protected $table = 'user';
protected $returnType = 'array';
protected $allowedFields = ['name', 'email', 'password'];
protected $createdField = 'created_at';
protected $updatedField = 'updated_at';
}
If you haven't change your directory names in app, you need to change namespaces from App\Model\Users (without "s" at the end) to App\Model\User.
Namespaces should follow directory structure, unless you change (or extends) CI4's core classes or at least app/Config/Autoload.php
Extends your model with CI_Model for it will be recognized .
class Auth_model extends CI_Model {
//you can always put function construct
public function __construct (){
parent::__construct ();
}
}
In controller :
class User extends CI_Controller {
public function __construct () {
parent:: __construct();
//you can load here the model that you will just often so will load it everytime to use it in a function
$this->load->auth_model('model-name(exam- public function test_uer()');
}
}
i'm tring laravel Modules and Repository.I had created Repository in App and Controller in module. But when controller call Repository it report "ReflectionException
Class Modules\Product\Http\Controllers\ProductEntryRepository does not exist".
But ProductEntryRepository in App\Reppsitory but it error in Controlller.
namespace Modules\Product\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use \App\Repositories\ProductCategoryRepository;
use \App\Repositories\ProductCategoryEntryRepository;
class ProductCategoryController extends Controller
{
/**
* #var PostRepository
*/
protected $request;
protected $product_category;
protected $product_category_entry;
public function __construct(Request $request, ProductCategoryRepository $product_category, ProductEntryRepository $product_category_entry){
$this->request = $request;
$this->product_category = $product_category;
$this->product_category_entry = $product_category_entry;
}
/**
* Display a listing of the resource.
* #return Response
*/
public function index()
{
return view('product::index');
}
You should just add use \App\Repositories\ProductEntryRepository; at the top of your controller :)
namespace Modules\Product\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\Response;
use Illuminate\Routing\Controller;
use \App\Repositories\ProductCategoryRepository;
use \App\Repositories\ProductCategoryEntryRepository;
use \App\Repositories\ProductEntryRepository;
class ProductCategoryController extends Controller
{
//......
}
Or i think you mean ProductCategoryEntryRepository not ProductEntryRepository in the construct !!
public function __construct(Request $request, ProductCategoryRepository $product_category, ProductCategoryEntryRepository $product_category_entry){
$this->request = $request;
$this->product_category = $product_category;
$this->product_category_entry = $product_category_entry;
}
I Want to extend Symfony2 Controller to my project that is using API but I am having error of a non object use getParameter() function look at my code:
namespace Moda\CategoryBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ApiController extends Controller
{
/**
* #var String
*/
protected $_host;
/**
* #var String
*/
protected $_user;
/**
* #var String
*/
protected $_password;
public function __construct()
{
$this->_host = $this->container->getParameter('api_host');
$this->_user = $this->container->getParameter('api_user');
$this->_password = $this->container->getParameter('api_password');
}
}
And next Controller
namespace Moda\CategoryBundle\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
class CategoryController extends ApiController
{
/**
* #Route("/category", name="_category")
* #Template()
*/
public function indexAction()
{
return array('name' => 'test');
}
}
And the end, I got this Fatal Error:
FatalErrorException: Error: Call to a member function getParameter()
on a non-object in (..)
I try to use $this->setContainer() but it doesn't work. Do you have any idea how can I slove this problem?
If your controller is not defined as service, The constructor execution of the controller is not persisted.
You have two options to solve your situation:
Define the controller as a service and inject the parameters you need using dependency injection.
Add an init method in the controller, or on a parent abstract controller, and call the init method, before the action you need to have these parameters available;
You cant use container in Controller __construct at reason that when constructor called where is none container set yeat.
You can simply define some simple methods in controller like
class ApiController extends Controller
{
protected function getApiHost()
{
return $this->container->getParameter('api_host');
}
}
I wonder if something crazy like this would work? Instead of overriding the constructor, override the setContainer method? I haven't tried it...just thinking out loud.
namespace Moda\CategoryBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\DependencyInjection\ContainerInterface;
class ApiController extends Controller
{
/**
* #var String
*/
protected $_host;
/**
* #var String
*/
protected $_user;
/**
* #var String
*/
protected $_password;
public function setContainer(ContainerInterface $container = null)
{
parent::setContainer($container);
$this->_host = $this->container->getParameter('api_host');
$this->_user = $this->container->getParameter('api_user');
$this->_password = $this->container->getParameter('api_password');
}
}