Netbeans PHP parent class code completion - php

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.

Related

CodeIgniter 4: Autoload Library

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.

Symfony 3 view overloading for controller inheritance

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
}
}
}

Use phalcon classes in base controller rather than on individual controllers

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.

DRY MVC view/controller separation

I have a custom MVC PHP framework that has a router class, which calls a controller, which uses a model, then the controller presents the view, etc etc.
My problem is that I can't figure out technically how to allow variables to pass between the controller and the view, semantically. I could do a quick-and-dirty fix, but what I want to have is this for a controller:
class IndexController extends Controller{
var $name = "John"; // instance variable
}
And have this for a view:
<p> <?=$name?> </p>
My question is this:
How can I create a Controller->render() function, or something similar, that allows the view to access instance variables from the controller? and,
How can I do this without doing klutzy things like $data['view']['name'] = "John"; or having to write ten lines of code by default for any new controller I make. I want to do this so it's as DRY as possible.
Thanks.
Edit: FabioCosta's solution
I'm not sure I understand, so far I have my base controller like this:
<?php
class Controller{
public function __get($key){
if(isset($this->$$key)) return $this->$$key;
}
}
?>
My base view class looks like this:
<?php
class View{
public $controller;
public function render(){
$this->controller = $this;
}
?>
And I initialize from the router like this:
<?php
$controller = new IndexController();
$view = new IndexView();
$view->render();
?>
However, this doesn't work, and I know I'm doing something wrong.
Why not pass the controller that instantiates the view and use the __get magic method?
like so:
public function __get($key){
if(isset($this->$key)) return $this->$key;
}
Here is a working example View.php:
class View{
protected $_controller;
public function __construct(Controller $controller){
$this->_controller=$controller;
}
public function render(){
echo '<h1>Hello '.$this->_controller->name.'</h1>';
}
}
Controller.php
class Controller{
protected $name='fabio';
protected $_myView;
public function __get($key){
if(isset($this->$key)) return $this->$key;
}
public function __construct(){
$this->_myView=new View($this);
}
public function indexAction(){
$this->_myView->render();
}
}
And the router:
$c=new Controller();
$c->indexAction();
Controller should not be responsible for rendering output. That is something view instances should do. Rendering should happen outside the controller.
View should request data from model layer. Then, based on information it received, select the right template, assign data and render this template (or in some cases - group of templates).
Also , router should not initialize neither controllers nor views. Controller should be responsible only for processing the request.

Can't access property in abstract class via sub class

I am trying to build an abstract base controller that will extend all other controllers. So far I have something like:
abstract class BaseController {
protected $view;
protected $user;
public function __construct() {
$this->view = new View; //So a view is accessible to subclasses via $this->view->set();
$this->user = new User; //So I can check $this->user->hasPermission('is_admin');
}
abstract function index();
}
class UserController extends BaseController {
public function index() {}
public function login() {
if($this->user->isLoggedin()) {
redirect to my account
}
else {
$this->view->set('page_title', "User Login");
$this->view->set('sidebar', $sidebar); //contains sidebar HTML
$this->view->set('content', $content); //build main page HTML
$this->view->render();
}
}
}
The problem i get is I get errors like this:
Call to a member function set() on a non-object in C:\xampp\htdocs\program\core\controllers\admin.controller.php on line 44
If I put the $user and $views properties in the main controller (ie UserController), everything works fine. But I only want to set up these objects once (in the base controller) and not have to add $this->view = new View; in all my controllers.
FIXED: I overrode my constructors and I thought you couldn't call parent::__construct() on abstract classes.
What you are trying to do should work. Make sure you aren't covering up your constructor in UserController. (i.e., if it has a constructor, it needs to call its parent constructor.)
Otherwise, do some debugging to see where $this->view is being reset.
Your code works for me. You are either overriding your __construct() method in UserController, or you are overridding the view field with something other than a View object.
What you have in this form would work.

Categories