I'm using the latest 'master' branch of CodeIgniter 4
I have a Library that I'm trying to load automatically. Effectively, I want to have have 'one' index.php (that has meta, the basic html structure, etc) through which I can load views via my 'Template' Library.
My Library file: (~/app/Libraries/Template.php)
//class Template extends CI_Controller
class Template {
/* This throws an error, but I will open up a separte thread for this
public function __construct() {
parent::__construct();
}
*/
public function render($view, $data = array()) {
$data['content_view'] = $view;
return view('layout/index', $data);
}
}
I also have a controller set up:
class Locations extends BaseController
{
public function index()
{
return $this->template->render("locations/index", $view_data);
//return view('locations/index');
}
//--------------------------------------------------------------------
}
In ~/app/Config/ I added my Library
$classmap = [
'Template' => APPPATH .'/Libraries/Template.php'
];
I'm getting the following error:
Call to a member function render() on null
What am I doing wrong that's causing my library not to load?
In CI4 the BaseController is where you create things that you want to be used by multiple other controllers. Creating classes that extend others is so very easy in CI4.
It seems to me that the only thing you are missing is creating the Template class. (There are a couple of other minor things too, but who am I to point fingers?)
One big item that might be just that you don't show it even though you are doing it. That is using namespace and use directives. They are must-do items for CI 4.
Because of where you have put your files you don't need and should remove the following. See how I've used use which imports namespace already known to the autoloader.
$classmap = [
'Template' => APPPATH .'/Libraries/Template.php'
];
First, the BaseController
/app/Controllers/BaseController.php
<?php
namespace App\Controllers;
use CodeIgniter\Controller;
use App\Libraries\Template;
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 = [];
protected $template;
/**
* Constructor.
*/
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->template = new Template();
}
}
/app/Controllers/Locations.php
class Locations extends BaseController
{
public function index()
{
// set $viewData somehow
$viewData['someVar'] = "By Magic!";
return $this->template->render("locations/index", $viewData);
}
}
/app/Libraries/Template.php
<?php namespace App\Libraries;
class Template
{
public function render($view, $data = [])
{
return view($view, $data);
}
}
/app/Views/locations/index.php
This works as if... <strong><?= $someVar; ?></strong>
I know I haven't created exactly what you want to do. But the above should get you where you want to go. I hope so anyway.
It's tricky at first.
But I managed to run it successfully
Make sure you give it proper namespace
And then just "use" in your controller Location.
I dont change anything on Autoload.php.
app/Libraries/Template.php
<?php
namespace App\Libraries;
class Template {
public static function render($param) {
return 'Hello '.ucwords($param);
}
}
The proper way to call is put use App\Libraries\Template just before class Location extends BaseController
app/Controllers/Locations.php
<?php
namespace App\Controllers;
use App\Libraries\Template;
class Locations extends BaseController {
public function index() {
$template = new Template();
$renderedStuff = $template->render('World!');
echo $renderedStuff;
}
}
How does this work?
Notice in Template.php there is a namespace namespace App\Libraries;, so CI4 will automatically load that library properly also recognize the "Template" class. That is proper way to create CI4 libraries in my point of view.
How do we use that library?
Look at my example of Locations.php and then see this code use App\Libraries\Template;, that's how we call that libraries.
How do we call the function?
Look inside the index() function, here we call class Template using var $template = new Template();.
Then we call render() function in Template library with $template->render('World!');.
Just as simple as that.
I hope thats help, lemme know if it doesnt works. :)
Just a little hint, as my eye was hooked by the CI_Controller part.
You seems to use CI3 syntax within CI4, at least about loading the view, which translates to just:
$data = [
'title' => 'Some title',
];
echo view('news_template', $data);
See the CI3doc vs the CI4doc , the "static page" tutorial.
Related
My goal is to include codes from another sources which is located in resources/views. I have tried using resource_path('views/myfiles.php') but it does nothing.
Controller
class MyController extends Controller
{
public function test(Request $request)
{
if($request->input('name') == "chair")
{
$theFilesLocation = "resources.views" . $request->input('name');
#include($theFilesLocation) //something like this
}
}
}
myfiles.php
<?php
dump("if this shows up, then the code works")
?>
Try bellow code but I think it is not a good way.
class MyController extends Controller
{
require_one(resource_path('views/myfile');
}
Or with Laravel File facade
class MyController extends Controller
{
\File::requireOnce(resource_path('views/myfile');
}
You should create a class and put your code there then call it from the controller is a better solution.
What you are looking for is a trait. This allows the easy sharing of code and functionality without having to inherit from a specific base class causing an inheritance hell.
namespace MyCode\Traits;
trait SharedCodeForThing {
public function blaTheBla() {
dump("if this shows up, then the code works");
}
}
and then in your controller
use MyCode\Traits\SharedCodeForThing ;
class MyController extends Controller
{
use SharedCodeForThing;
}
Now if you wish to just render the contents of the view which it seems you're after:
public function test(Request $request)
{
if($request->input('name') == "chair")
{
$view = view('resources.views' . $request->input('name'));
return $view->render();//or echo $view->render(); whatever you like
}
}
I am writing system for players where I use Laravel freamwork (just for learn) and I have question for more experience developer. I have one function which return me some data to view. I use this function in 3 controllers (but i copy and paste this function to each Controller files) and can I just put this function in one file and then use it in these 3 controllers? How can I use the same function in diffrent controller without copy and past?
You can also use Traits to share methods, however, traits are more usually for describing characteristics and types.
You should create a utility class, or use consider an abstract controller class if this is desired.
You can create Base Controller:
<?php
namespace App\Http\Controllers;
class BaseController
{
protected $playersRepository;
public function __construct(PlayersRepository $playersRepository)
{
$this->playersRepository = $playersRepository;
}
}
Which is injected with a repository object:
<?php
namespace App\Http\Controllers;
class PlayersRepository
{
public function getPlayers()
{
return Player::all();
}
}
Which has a common method, that can be used in more than one extended controller:
Games
<?php
namespace App\Http\Controllers;
class Games extends BaseController
{
public function index()
{
return view('games', ['players' => $this->playersRepository->getPlayers()]);
}
}
Matches
<?php
namespace App\Http\Controllers;
class Matches extends BaseController
{
public function show()
{
return view('matches', [
'matches' => $matches,
'players' => $this->playersRepository->getPlayers()
]);
}
}
Create module (util) or override main Controller class.
I am using Netbeans for a custom PHP project and code completion does not work properly. Any help will be wonderful. This is my scenario.
A summary of the View class.
use Smarty;
Class View extends Smarty
{
public function render($template)
{
$this->display('$template);
}
}
A summary of the Controller class.
use View;
Class Controller
{
/* #var $view View */
public $view;
public function __construct()
{
$this->view = new View;
}
$this->view-> // Netbeans show all methods from View and Smarty Class.
}
In my individual Controllers.
use Controller;
Class IndexController extends Controller
{
$this->view-> // Does NOT show anything either from View or Smarty Class.
}
Thanks a lot for your help.
How to load a Model inside a Component in Cakephp 3.0?
Before(in Cakephp 2) you could use
$Model = ClassRegistry::init($modelName);
$Model->create(false);
$saved = $Model->save($data);
Whats the equivalent of that in 3.0?
As pointed out before, you can use the TableRegistry to access a model:
use Cake\ORM\TableRegistry;
$this->Articles = TableRegistry::get('Articles');
See here for documentation.
As someone said in the comments, you should at least read the migration guide to understand what the differences with 3.0 are. To address your specific question, you now can use the TableRegistry:
$table = TableRegistry::get($tableName);
Accessing a Component’s Controller
From within a Component you can access the current controller through the registry:
$controller = $this->_registry->getController();
for more please read this link : http://book.cakephp.org/3.0/en/controllers/components.html
One thing that I've done is to build a loadModel class in the component. This keeps my code consistent.
namespace App\Controller\Component;
use Cake\Controller\Component;
use Cake\ORM\TableRegistry;
class MyComponent extends Component {
public function initialize(array $config) {
parent::initialize($config);
$this->loadModel('Users');
}
private function loadModel($model) {
$this->$model = TableRegistry::get($model);
}
}
If you insist to use loadModel which adds the instance to the controller as a property then that's how you do it.
class ArticleComponent extends Component
{
public function initialize(array $config)
{
$this->controler = $this->_registry->getController();
}
public function myFunction($id)
{
$this->controller->loadModel('Articles');
$article = $this->controller->Articles->get($id);
debug($article);
}
}
This way is like telling controller to open a model for you:
$article = $component->controller->UserModel;
But when you can call a model straight away using TableRegistry what's the point of calling controller to call a model for you.
$article = $component->UserModel;
Long story short loadModel() is a wrapper for TableRegistry
my answer is same approch other answers. but, I try to save record inside component.
In this case, code is like following...
use Cake\ORM\TableRegistry;
---
$model = TableRegistry::get('MyModeles');
$entity = $model->newEntity();
$entity->set('filed1', 'newValue');
....
$model->save($entity);
You can dynamic access to table with the next snippet:
use Cake\Event\Event;
use Cake\Controller\Component;
use Cake\ORM\TableRegistry;
class TestComponent extends Component {
private $controller;
private $table;
public function startup(Event $event) {
$this->controller = $event->getSubject();
$this->table = TableRegistry::get($this->controller->name);
}
}
I have a base controller as follows
<?php
use Phalcon\Mvc\Controller;
class ControllerBase extends Controller {
public function initialize() {
}
// wrapper function for debug purposes.
public function pr($data = null) {
echo '<pre>';
print_r($data);
echo '</pre>';
}
}
and a users controller as follows
<?php
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model as Paginator;
use Phalcon\Mvc\View;
class UsersController extends ControllerBase {
public function initialize() {
// initialize parent, here ControllerBase.
parent::initialize();
}
public function loginAction() {
// disable the main layout.
$this->view->disableLevel(View::LEVEL_MAIN_LAYOUT);
// disable the controller layout.
$this->view->disableLevel(View::LEVEL_LAYOUT);
}
.
.
.
.
other functions...
}
i was wondering if i could call all the required phalcon classes in base controller and extend then to all the child classes so that i dont need to call them individually on each controller.
in otherwords, can i add the below code
use Phalcon\Mvc\Model\Criteria;
use Phalcon\Paginator\Adapter\Model as Paginator;
use Phalcon\Mvc\View;
only in the base controller and acces them in other controllers. I tried putting them base controller but it gave error : Class not found.
Is this the right way or is there something wrong in my approach...please help.
If I understand your question correctly the answer is NO.
Namespaces are language feature and works this way. The use Phalcon\Mvc\Model\Criteria only declares that you'll use Criteria class from Phalcon\Mvc\Model\ namespace. So in your code you can write new Criteria() to create object instead of using its' full name new \Phalcon\Mvc\Model\Criteria().
You must declare each class in every file which instantiates object of that class so autoloader will know in which file given class exists.