How can I load a model in ...\app\Config\Autoload.php?
Code:
namespace Config;
use CodeIgniter\Config\AutoloadConfig;
class Autoload extends AutoloadConfig {
public function __construct() {
//load here
//i've tried,
$my_model = new \App\Models\My_model();
$my_model = model("App\Models\My_model");
}
Nothing is working.
What is the correct way?
Looking for help.
Thanks in advance.
This really depends on where you want to use this model. Autoloading does not work the same way as codeigniter 3 where everything would be put into the same super object.
If what you want is to use this model in a bunch of controllers then you can add that to your baseController in your initController function. Let's say you want to autoload the article model:
public $article;
public function initController(\CodeIgniter\HTTP\RequestInterface $request, \CodeIgniter\HTTP\ResponseInterface $response, \Psr\Log\LoggerInterface $logger)
{
// Do Not Edit This Line
parent::initController($request, $response, $logger);
$this->article = new \App\Models\ArticleModel();
}
Now all your controllers that extend to your baseController can access this model with $this->article.
If what you want is to use the autoload and you can do that too, but not in a construct, for that you should use the classMap property.
/**
* -------------------------------------------------------------------
* Class Map
* -------------------------------------------------------------------
* The class map provides a map of class names and their exact
* location on the drive. Classes loaded in this manner will have
* slightly faster performance because they will not have to be
* searched for within one or more directories as they would if they
* were being autoloaded through a namespace.
*
* Prototype:
*
* $classmap = [
* 'MyClass' => '/path/to/class/file.php'
* ];
*
* #var array
*/
public $classmap = [
'Article' => APPPATH . 'Models/ArticleModel.php'
];
But this option is more for classes that exist outside the normal codeigniter structure. So I would advise into using the first option.
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.
I need to access some data (User details) in most views. What I have done:
I created ComposerServiceProvider
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ComposerServiceProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* #return void
*/
public function boot()
{
view()->composer(
['includes.header','profile'],
'App\Http\ViewComposers\CustomerComposer'
);
}
/**
* Register the application services.
*
* #return void
*/
public function register()
{
//
}
}
Created CustomerComposer class
<?php
namespace App\Http\ViewComposers;
use Illuminate\Support\Facades\Auth;
use Illuminate\View\View;
use Modules\Customers\Entities\CustomerDetail;
class CustomerComposer
{
public $customer = [];
/**
* Bind data to the view.
*
* #param View $view
* #return void
*/
public function compose(View $view)
{
$user = Auth::guard('customer');
$this->customer = CustomerDetail::where('user_id',$user->id())->first();
$view->with( 'customer', $this->customer );
}
}
Everything works but when I look at Debug bar it shows me same queries excecuted per view, so for example if I define ['includes.header','profile'] Same SQL will be excecuted twice if ['includes.header','profile','something_else'] 3 times and so on...
In this case query's is
select * from `customer_details` where `user_id` = '1' limit 1
select * from `customer_details` where `user_id` = '1' limit 1
If I provide wildcard in
view()->composer(
['*'],
'App\Http\ViewComposers\CustomerComposer'
);
It will generate 23 queries! I missed something here?
Ok I think I found solution. In ComposerServiceProvider class:
/**
* Register the application services.
*
* #return void
*/
public function register()
{
$this->app->singleton(\App\Http\ViewComposers\CustomerComposer::class);
}
That it.
In Laravel Docs
Registering A Singleton
Sometimes, you may wish to bind something into the container that
should only be resolved once, and the same instance should be returned
on subsequent calls into the container:
Per the manual at https://laravel.com/docs/5.5/views#view-composers:
"View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view composer can help you organize that logic into a single location."
(emphasis mine)
In this case:
view()->composer(
['includes.header','profile'],
'App\Http\ViewComposers\CustomerComposer'
);
you're attaching the includes.header view and the profile view, which I guess includes the includes.header view. So, since the composer is executed when the view is rendered, it'll execute twice, one when rendering of the profile view and again another when rendering the includes.header view.
You can use config here to resolve multiple times query run issue for view compose. For example show below code.
public function compose(View $view)
{
if(!Config::has('composeVars'))
{
Config::set('composeVars') = [
'users' => User::all();
];
}
$view->with('*', Config::get('composeVars'));
}
I'd like to retrieve my module configuration from a controller in Zend Framework 3.
I searched, and it seems that the standard way to do this in ZF2 is to use
$this->getServiceLocator()
to access the configuration in module.config.php.
However, this won't work in ZF3, as there is no getServiceLocator() method.
What is the standard way to achieve this?
Don't know if you found an answer, as there are different solutions as tasmaniski wrote. Just in case, let me share one that would have helped me a lot when I started to play with ZF3:
MyControllerFactory.php
<?php
namespace My\Namespace;
use Interop\Container\ContainerInterface;
use Zend\ServiceManager\Factory\FactoryInterface;
use DependencyNamespace\...\ControllerDependencyClass; // this is not a real one of course!
class MyControllerFactory implements FactoryInterface
{
/**
* #param ContainerInterface $container
* #param string $requestedName
* #param null|array $options
* #return AuthAdapter
*/
public function __invoke(ContainerInterface $container, $requestedName, array $options = null)
{
// Get config.
$config = $container->get('configuration');
// Get what I'm interested in config.
$myStuff = $config['the-array-i-am-interested-in']
// Do something with it.
$controllerDepency = dummyFunction($myStuff);
/*...the rest of your code here... */
// Inject dependency.
return $controllerDepency;
}
}
MyController.php
<?php
namespace My\Namespace;
use Zend\Mvc\Controller\AbstractActionController;
use DependencyNamespace\...\DependencyClass;
class MyController extends AbstractActionController
{
private $controllerDepency;
public function __construct(DependencyClass $controllerDepency)
{
$this->controllerDepency = $controllerDepency;
}
/*...the rest of your class here... */
}
You need to inject your dependencies through service manager.
Basicly you need to create 2 class Controller and ControllerFactory that will create Controller with all dependencies.
I have been doing a read up on ZF2 Service Locator component and could say I understand how its being used. I have, however, a question which I think its silly but it wouldn't hurt to ask.
I want to have a namespace inside my Module called Component where I can put generic code in like say FunctionsComponent.php, MailerComponent.php or ExcelComponent.php. This would allow me to do some stuff inside my controllers.
What I would like to tryout is to have an ability to have controllers define the components they are interested to use (see below):
class SalesController extends AbstractController
{
protected $components = ['Excel'];
//In some action
public function exportAction()
{
$data = ['data to be exported'];
/**
$data : data to be exported
boolean : Whether to force download or save the file in a dedicated location
*/
$this->Excel->export($data, true);
}
}
The idea is to create a ComponentCollection that perhaps implements the FactoryInterface or ServiceLocatorInterface and then let it check each controller when the MvcEvent has been triggered inside my Module class and have the ComponentCollection inject all the controller component and make them accessible without using the service locator as shown below:
$excel = $sm->get('Application\Component\Excel');
I am well aware that this may seem like a daunting ask but I feel like the best way to learn a framework among other things is to play around with it and try to do the unimaginable.
You should create a BaseController somewhere and then extend all your Controllers from BaseController. Then you can inject your dependencies in your BaseController and use anywhere in kids. For example, I am doing this in my Controller to set head title:
<?php
namespace Application\Controller;
use Zend\Mvc\Controller\AbstractActionController;
class BaseController extends AbstractActionController
{
/**
* Sets the head title for every page
*
* #param string $title
*/
public function setHeadTitle($title)
{
$viewHelperManager = $this->getServiceLocator()->get('ViewHelperManager');
// Getting the headTitle helper from the view helper manager
$headTitleHelper = $viewHelperManager->get('headTitle');
// Setting a separator string for segments
$headTitleHelper->setSeparator(' - ');
// Setting the action, controller, module and site name as title segments
$siteName = 'Ribbon Cutters';
$translator = $this->getServiceLocator()->get('translator');
$title = $translator->translate($title);
$headTitleHelper->append(ucfirst($title));
$headTitleHelper->append($siteName);
}
}
Instead of defining methods, you can define properties.
public $headTitleHelper
and assign it in constructor of BaseController
$this->headTitleHelper = $this->getServiceLocator()->get('ViewHelperManager')->get('headTitle');
Now you can use $this->headTitleHelper in child controllers.
And then
<?php
namespace Application\Controller;
use Zend\View\Model\ViewModel;
use Application\Controller\BaseController;
class IndexController extends BaseController
{
/**
* Property for setting entity manager of doctrine
*/
protected $em;
/**
* landing page
*
* #return ViewModel
*/
public function indexAction()
{
$this->setHeadTitle('Welcome'); // Welcome - Ribbon Cutters
$viewModel = new ViewModel();
return $viewModel;
}
/**
* Sets and gives Doctrine Entity Manager
*
* #return Doctrine Entity Manager
*/
protected function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('doctrine.entitymanager.orm_default');
}
return $this->em;
}
}
I think this can help you.
Here is the beginning of my controller code:
<?php
class AppController extends BaseController {
/**
* App Model
* #var app
*/
protected $app;
/**
* User Model
* #var User
*/
protected $user;
/**
* Inject the models.
* #param app $app
* #param User $user
*/
public function __construct(App $app, User $user)
{
parent::__construct();
$this->app = $app;
$this->user = $user;
}
In my models folder I have a file called App.php
Here is the beginning of the code:
<?php
use Illuminate\Support\Facades\URL; # not sure why i need this here :c
use Robbo\Presenter\PresentableInterface;
class App extends Eloquent implements PresentableInterface {
Now I did a var_dump() of the $this->app var and I got this:
object(Illuminate\Support\Facades\App)#472 (0) { }
I am not sure why it's trying to get a Facades when It's supposed to get my model.
Also here is a part of my routes file:
/** ------------------------------------------
* Route model binding
* ------------------------------------------
*/
Route::model('user', 'User');
Route::model('app', 'App');
Route::model('role', 'Role');
# Apps - Second to last set, match slug
Route::get('{appSlug}', 'AppController#getView');
Route::post('{appSlug}', 'AppController#postView');
# Index Page - Last route, no matches
Route::get('/', 'AppController#getIndex');
I assume that the rest is irrelevant. But if not, do please ask for the rest.
This is because of the IoC container. App is already taken by the main application. What you could do is add an alias in app/config/app.php
'aliases' => array(
... current aliases,
'AppModel' => 'Robbo\Models\App'
);
Of course the App model needs to be namespaced to Robbo\Models in this case.