Let's say I have 2 controllers, content and news:
class ContentController extends Symfony\Bundle\FrameworkBundle\Controller\Controller {
public function indexAction() {}
}
and
class NewsController extends ContentController {}
If the view for the indexAction does not exist for the news controller (the indexAction is inherited from the parent class), I want Symfony to use the view of the Content controller (indexAction). How can I achieve this?
Symfony always tries to render the view News/index.html.php but if this view does not exist I would like that Symfony renders Content/index.html.php.
Is it possible to tell the Symfony render engine something like this: If there exists the file News/index.html.php take this one, otherwise take Content/index.html.php
I'm using the PHP template engine, not twig.
We are currently using the Zend Framework and there you can simply add a script (view) path as described here View overloading in Zend Framework
I hope I understand you correctly and this could fix you problem:
class ContentController extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
/**
* #Route("/", name="content_index")
*/
public function indexAction()
{
// render Content/index.html.php
}
}
class NewsController extends ContentController
{
/**
* #Route("/news", name="content_news_index")
*/
public function indexAction()
{
parent::indexAction();
// render News/index.html.php
}
}
You have to adjust the routes to your needs.
Additional approach as requested in the comments:
use Symfony\Component\HttpFoundation\Request;
class ContentController extends Symfony\Bundle\FrameworkBundle\Controller\Controller
{
/**
* #Route("/", name="content_index")
* #Route("/news", name="content_news_index")
*/
public function indexAction(Request $request)
{
$routeName = $request->get('_route');
if ($routeName === 'content_index') {
// render Content/index.html.php
} elseif ($routeName === 'content_news_index') {
// render News/index.html.php
}
}
}
Related
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.
I have a the following in mysite/code/Page.php:
...
class Page_Controller extends ContentController {
public function init() {
parent::init();
Requirements::javascript("themes/example/js/global1.js");
Requirements::javascript("themes/example/js/global2.js");
Requirements::javascript("themes/example/js/global3.js");
}
}
...
and then a custom controller in mysite/controllers/PlayController.php:
...
class PlayController extends ContentController {
public function init() {
parent::init();
Requirements::javascript("themes/example/js/play.js");
}
}
...
I would like to use the Requirements from Page.php in PlayController.php. Since they both extend ContentController, is this possible?
A little background; PlayController is used to display a page for a theatre play with the template Layout/PlayPage.ss. If I put the Requirements in templates/Page.ss, they are inherited by PlayPage.ss. But I'd like to put the Requirements in a controller, so I can use Silverstripe's combine_files feature. Hope this makes sense!
Thanks :-)
You could create a subclass of ContentController that can serve as the base-class for both of your controllers. Eg. you create a MyController extends ContentController and then PlayController and Page_Controller extend MyController.
Or you could just require all the files in both controllers… if that's too much redundancy, you could also use the config API for this. Here's an example:
class Page_Controller extends ContentController
{
private static $js_requirements = [
"themes/example/js/global1.js",
"themes/example/js/global2.js",
"themes/example/js/global3.js"
];
public function init() {
parent::init();
foreach ($this->config()->js_requirements as $js) {
Requirements::javascript($js);
}
}
}
And then in your PlayController, you could access the config of Page_Controller like so:
class PlayController extends ContentController
{
public function init() {
parent::init();
foreach (Config::inst()->get('Page_Controller', 'js_requirements') as $js) {
Requirements::javascript($js);
}
Requirements::javascript("themes/example/js/play.js");
}
}
You could then also use the YAML config to configure your requirements, eg.:
# mysite/_config/config.yml
Page_Controller:
js_requirements:
- "themes/example/js/global4.js"
Note: Always use dev/build, so that your config variables are being picked up.
I have my normal mvc directory's at codeigniter like:
Models
Views
Controllers
But I use the wiredesigz "plugin" for hmvc support, so I have this structure:
Models
Views
Controllers
Modules
TestModule
Models
Views
Controllers
I have this code at my root controllers folder:
class Core_Test_Controller extends MX_controller
{
public function __construct()
{
parent::__construct();
}
public function getText() {
return "hi";
}
}
And this at the /Modules/TestModule/Controllers:
class InsertController extends MX_Controller
{
public function __construct(){
parent::__construct();
}
function testIt{
$coreTestController = new $this->Core_Test_Controller();
$text = $coreTestController->getText();
print_r($text);
}
}
But I get the error that class Core_Test_Controller is not found. Why can't I acces that controller from another controller? Is this even possible?
Fixed it:
Modules::load('../Core_Test_Controller/')->getText();
First off lower case for folder names. Only first letter must be upper case for controller names and models etc UCFIRST as explained here http://www.codeigniter.com/user_guide/general/styleguide.html#file-naming HMVC wont pick up CI_Controllers controllers only MX_Controllers
class Core_test_controller extends MX_controller {...}
class Insertcontroller extends MX_Controller {...}
As said here
<?php
/** module and controller names are different, you must include the method name also, including 'index' **/
modules::run('module/controller/method', $params, $...);
/** module and controller names are the same but the method is not 'index' **/
modules::run('module/method', $params, $...);
/** module and controller names are the same and the method is 'index' **/
modules::run('module', $params, $...);
/** Parameters are optional, You may pass any number of parameters. **/
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.
My question is, how can I inherit Controllers action in YII, like:
class MainController extends FController
{
public function ActionIndex()
{
$this->render("index"); //the view;
}
}
--------------------------------------------
class SecondController extends FController
{
public function ActiondIndex()
{
MainController::ActionIndex();
}
}
Actually in my case the SecondController is the DefaultController of a sub-module. I want to make single code based webpage.
Since PHP does not support multiple inheritance, you may access the base class via the parent keyword.
class MainController extends FController
{
public function ActionIndex()
{
$this->render("index"); //the view;
}
}
class SecondController extends FController
{
public function ActionIndex() // Note: you mistyped the name of this action in your example
{
parent::ActionIndex();
}
}
Although you cannot reach the grandparent's ActionIndex method directly, you have to create a workaround for that.