Consider under my cpp\controllers\ I've 5 files like (AController.php, BController.php etc..)
Each controller has its own public variable like this..
AController.php --- public $variable='Testing';
BController.php --- public $variable='Bhuvanesh';
From my app\views\main.php
If A controller is called I need the value Testing. If B controller is called I need Bhuvanesh.
Its possible in yii2? Thanks in advance.
You should read Yii2 Views Guide :
within the view you can get the controller object by the expression $this->context
So, you should simply use this in your view :
$this->context->variable
Why don't you create a getter method with same name?
class AController {
public function getVariable() { return 'A'; }
}
class BController {
public function getVariable() { return 'B'; }
}
class CController {
public function getVariable() { return 'C'; }
}
Then you can call with
$controller->variable
You could use the __construct() magic method? this function gets executed right when the class is used. If you make something like
public function __construct(){
echo $this->var; //echo out whatever you want here.
}
That's how i would do it.
Related
I have a problem like below:
I have an Interface name IBannerService
<?php
namespace App\Interfaces;
interface IBannerService
{
public function add($data);
public function list();
public function get($data);
public function delete($data);
}
and an instance name BannerService
class BannerService implements IBannerService
{
public function add($data)
{
return true;
}
public function list()
{
return true;
}
public function get($data)
{
return true;
}
public function delete($data)
{
return true;
}
public function test()
{
print_r("aaaa");
die();
}
}
finally I have a Controller name HomeController
class HomeController extends Controller
{
public function __construct(
IBannerService $bannerService
)
{
$this->bannerService = $bannerService;
}
public function index()
{
$listBanner = $this->bannerService->list();
$this->bannerService->test();
}
}
My configuration:
class DIServiceProvider extends ServiceProvider
{
$this->app->bind(
'App\Interfaces\IBannerService',
'App\Services\BannerService'
);
}
In app.php:
'providers'=>[
App\Providers\DIServiceProvider::class,
]
The code run well with $listBanner = true (just for testing).
The problem is:
Test Method was not declared in interface IBannerService but still go through and print out "aaa" the die.
Did I do something wrong?
Please suggest me, thank you!
That's perfectly normal functionality.
In the Laravel container you defined that when you ask for a IBannerService object, you want to get a BannerService class. And that is what you got. BannerService is an implementation of IBannerService, so no problem for the typehint.
A class is not limited to the functions defined by its interface so you can add as many other functions as you like. I wouldn't recommend it though, things like smart IDE's and phpstan would give you errors or warnings because to them, the variable is an implementation of IBannerService and this does not have a test() function.
If you really want to use more functions I would even recommend to use BannerService as the typehint. This way, static code analysis will still work.
I have problem, can i call constructor without create 'new class()' ? Or you maybe have another way for this :
<?php
class a
{
public static $hello;
public function say()
{
return self::$hello;
}
}
class b extends a
{
public function __construct()
{
self::$hello = 'hello world';
}
}
echo b::say();
?>
I have try with :
$b = new b();
echo $b->say();
And it's work. But i want to use b::say();
Can help me?
Thank you!!
Check out this. Is this good for you?
<?php
class a {
public static $hello;
public static function say() {
return self::$hello;
}
}
class b extends a {
public function __construct() {
self::$hello = 'hello world';
}
public static function factory() {
return new b();
}
}
echo b::factory()->say();
?>
Actually I couldn't find a way to do this without calling constructor. This is how the workaround looks like. factory is just a name. you can rename it.
calling class method (with constructors) without object instantiation in php
You have asked: "can i call constructor without create 'new class()' ?"The answer: No.
... Classes which have a constructor method call this method on each
newly-created object
You have requested "But i want to use b::say();"
b::say(); - is call of static method.You can't override non-static parent method to static. But you can restructure your base class class a to make say() method static.
<?php
class a
{
public static $hello;
public static function say()
{
return self::$hello;
}
}
class b extends a
{
public function __construct()
{
self::$hello = 'hello world';
}
}
The thing that you were missing was you needed to add your content to your new class method. - Just call it like so:
$b = new b('Some words');
echo $b->say();
When calling a new class and using a constructor - You will want to add the content in the paramaters for the new class you are making.
It acts as if you are calling the __construct function. - Calling new class($a) will call the __construct($a) function once making the object.
Hope that this helped a bit :)
Yes it is possible just make the say() function static like this :
public static function say()
{
return self::$hello;
}
Declaring class methods as static makes them accessible without needing an instantiation of the class.
This example looks to me like late static binding. So try changing that return self::$hello; into return static::$hello;
class TopParent
{
protected function foo()
{
$this->bar();
}
private function bar()
{
echo 'Bar';
}
}
class MidParent extends TopParent
{
protected function foo()
{
$this->midMethod();
parent::foo();
}
public function midMethod()
{
echo 'Mid';
}
public function generalMethod()
{
echo 'General';
}
}
Now the question is if I have a class, that extends MidParent because I need to call
class Target extends MidParent
{
//How to override this method to return TopParent::foo(); ?
protected function foo()
{
}
}
So I need to do this:
$mid = new MidParent();
$mid->foo(); // MidBar
$taget = new Target();
$target->generalMethod(); // General
$target->foo(); // Bar
UPDATE
Top parent is ActiveRecord class, mid is my model object. I want to use model in yii ConsoleApplication. I use 'user' module in this model, and console app doesn't support this module. So I need to override method afterFind, where user module is called. So the Target class is the class that overrides some methods from model which uses some modules that console application doesn't support.
Try this (http://php.net/manual/en/language.oop5.final.php - not allow to overriding in the childrens):
final protected function foo()
{
$this->midMethod();
parent::foo();
}
in class MidParent and the class Target can't overrides this method.
Directly - you can't. This is how OOP works.
You can do it by a little redesign, e.g. in MidParent add method:
protected function parentFoo()
{
parent::foo();
}
and in Target:
public function foo()
{
$this->parentFoo();
}
But, again, this is only a workaround to solve your question and not a solution.
Actually, you can do this like this way with Reflection::getParentClass():
class Foo
{
public function test($x, $y)
{
echo(sprintf('I am test of Foo with %s, %s'.PHP_EOL, $x, $y));
}
}
class Bar extends Foo
{
public function test()
{
echo('I am test of Bar'.PHP_EOL);
parent::test();
}
}
class Baz extends Bar
{
public function test()
{
$class = new ReflectionClass(get_class($this));
return call_user_func_array(
[$class->getParentClass()->getParentClass()->getName(), 'test'],
func_get_args()
);
}
}
$obj = new Baz();
$obj->test('bee', 'feo'); //I am test of Foo with bee, feo
-but this is an architecture smell in any case. If you need something like this, that should tell you: you're doing something wrong. I don't want to recommend anyone to use this way, but since it's possible - here it is.
#AnatoliyGusarov, your question is interesting and in a sense you can achieve what you desire using yii and php advances features like Traits and Traits in Yii.
Given that it depends on what version of php you are using.However in yii you can achieve this by behaviors and check this SOQ.
In a nutshell you have to use language advanced features or YII framework features to come around this kind of issues,but that boils down to actual requirements
I am trying to write an extension to my Controller class. The problem is I can't seem to figure out how..
I have the following class named test in which there is one function which simply returns aaaa and in in the same file, at the end, as my Controller:
class test extends Controller
{
function test()
{
parent::Controller();
}
function echoMe(){
return 'aaaaaaaaaaaaaaaaa';
}
}
Within my Controller class I have a function which is the general output for a clients homepage. I'm trying to call the function echoMe from the extension above, but I keep getting
Call to undefined method Controller::echoMe()
Here is the client function (the call to echoMe() is right at the top):
function controller_client1($controlData = NULL)
{
echo $this -> echoMe();
//as the client page is content from the xml, mmodel needs the page number
$pageNumber = '';
if(isset($_GET['number']))
{
$num = htmlentities($_GET['number']);
if(ctype_digit($num) && $num >= 0)
{
$pageNumber = $num;
}
}
else{
$pageNumber = 0;
}
//loading the page content
$data = $this->model->model_loadXMLdata($pageNumber);
if(!empty($controlData))
{
//check if there is any info in the control data sent
foreach($controlData as $key => $value)
{
//add the info to the data array
$data[$key] = $value;
}
}
$this->load->load_clientHomePage($data);
}
I know this is a very simple question. I've been trying to follow this guide, but something isn't clicking...
Could somebody please help? How can I call the function echoMe() from test?
I know how to write just a brand new class and call it, but I'm trying to learn how to extend properly and keep failing.
Am I meant to call the "test" from within the Controller somewhere?
In the config.php you set the prefix for the file you want to extend. So it should be My_test, unless you have changed this preset(displayed below)
/*
|--------------------------------------------------------------------------
| Class Extension Prefix
|--------------------------------------------------------------------------
|
| This item allows you to set the filename/classname prefix when extending
| native libraries. For more information please see the user guide:
|
| http://codeigniter.com/user_guide/general/core_classes.html
| http://codeigniter.com/user_guide/general/creating_libraries.html
|
*/
$config['subclass_prefix'] = 'MY_';
Make sure you have the controller in the right folder (application/core in codeigniter 2.1.0) then you shouldn't have a problem. Hope that helps
here is my controller that i extend. The file is called My_Controller.php (creative I know)
<?php
class MY_Controller extends CI_Controller {
function __construct()
{
parent::__construct();
//constructor code here
}
//Custom functions here
}
//sencond controller I extend in the same file
class MY_Admin extends CI_Controller {
function __construct()
{
//more custom stuff for admin stuff
}
//more custom functions for admin stuff
}
?>
Has you see I have two extended controllers in the same file.
My extending code looks like this:
<?php
class home extends MY_Controller
{
and then just replace My_Controller with My_Admin if I want to extend the admin.
echoMe() function is defined in test class and not in Controller class. When controller_client1 function is called with the instance of Controller class, echoMe does not exist because it is not defined within Controller class.
The best way to achieve this is to create empty echoMe function in base Controller class. This way polymorphism works. When calling controller_client1 function from instance of test class, method from that class will be executed. Otherwise, method from base class will be executed.
I hope I didn't miss the point of the question :)
echo $this -> echoMe(); will fail because its created in the child(extended) class and your calling it in the parent class. The question is a little hard to understand.
abstract class Controller{
public function __construct(){
}
public function echoMe($str){
echo $str;
}
}
class test extends Controller{
public function __construct(){
parent::echoMe('aaaaaaaaaa');
}
}
Try this (general idea, not CodeIgniter only):
$test = new test();
echo $test->echoMe();
Remember, test extends your Controller class, not the other way round - so you can't call your methods outside the test class/object instance.
Also, it might be a good idea to upgrade to a new version of CodeIgniter - beware of the new parent controller name, though.
EDIT
Ok, this should be enought to get you started - note that it's PHP5, not PHP4, so constructors are called __construct and not the class name:
class Controller {
public $mainvar;
function __construct() {
$this->mainvar = '<br />';
}
function echoMe() {
return 'aaaaaaaaaaaaaaaaa';
}
}
class Test extends Controller {
function __construct() {
parent::__construct();
}
function echoMeAgain(){
return 'bbb';
}
}
$test = new Test();
echo $test->echoMe();
echo $test->mainvar;
echo $test->echoMeAgain();
I think the question has actually already been answered by Kosta, but there might be some misunderstanding at your side. So let me extend that by some example code:
class Controller {
public function run() {
$this->echoMe();
}
}
class test extends Controller {
public function echoMe() {
echo "works";
}
}
// This does NOT work, because Controller::echoMe does not exist
$controller = new Controller();
$controller->run();
// This DOES work, because $this will be instance of test, and
// test::echoMe exists and is callable.
$test = new Test();
$test->run();
"extends" does not mean, that the actual Controller class gets extended. The new class "test" just inherits every single method and property that is not declared "private" from the Controller class. The Controller class itself remains untouched.
Given a Controller class and a View class, is it better for the controller to directly assign values to view properties or, is it better to assign values to properties in the controller and then copy those properties to the view when ready to display it?
Example Model Class
class Model
{
public $propertyA;
public $propertyB;
}
Example Controller class:
class Controller
{
protected $view;
protected $model;
public function __construct()
{
$this->model = new Model();
$this->view = new View();
$this->prepareData();
$this->initView();
}
protected function prepareData()
{
$this->model->propertyA = 'This is property A.';
$this->model->propertyB = 'This is property B.';
}
protected function initView()
{
$this->view->model = $this->model;
$this->view->display();
}
}
Example View class:
class View
{
public $model;
public function display()
{
echo "propertyA = $this->model->propertyA";
echo "propertyB = $this->model->propertyB";
}
}
Sorry, I was tired. I do use a model, so please reconsider your answers with this in mind.
The data should only be in one place. If not when things get complicated it is hard to sync the different places you have the data. In MVC you have a model and that is where the data should be. Pass the Model into the View and have the view display that.
Here is a simple explanation: http://en.wikipedia.org/wiki/Model%E2%80%93View%E2%80%93Controller or here for those that do not like Wikipedia: http://ootips.org/mvc-pattern.html
The model can be as simple as a class with the properties in it.
The view shouldn't be setting up variables unless they are related to the presentation. It's best to put static variables in a config file anyway.
copy those properties to the view
Rather than setting variables in the view why don't you just construct the view with a reference to the controller. That should save you from writing a lot of boiler plate code.
Class Controller() {
$this->something = 'abc';
function __construct() {
$this->display();
}
function display() {
$this->view = new View($this);
}
}
Class View() {
function View(&$controller) {
$this->controller = $controller;
print $this->controller->something;
}
}
Edit: I like Romain Hippeau's answer a lot more than my own. You should pass the model into the view.