What's the easy way of calling model method in Yii2. Something like:
$a = User::model()->method();
Code like this:
$a = new User()->method();
don't work.
This is the very basic thing.
Calling model method in both Yii1 and Yii2 is similar and done like that:
$model = new User();
$model->method();
Note that for Yii2 you also need to specify namespace of User class.
The method must be public obviously.
If you don't want use variable assignment, you need to place brackets differently:
(new User)->method();
and not:
new User()->method();
This is PHP language feature, it has nothing to do with Yii framework.
And as for your particular case - model() in Yii1 is used for constructing queries with ActiveRecord.
Replacement for Yii2 is find() method, you can read about it in this question.
Since Yii 2.0.13 you can use instance() to get static instance of model. It works in similar way as model() in Yii 1.1 - creates model object only once and reuses it for every call. It should be faster and more readable than (new User())->method(), which will create separate model on every call.
User::instance()->method();
User::instance()->getAttributeLabel('some_attribute');
Here you can call a method as follows,
$a = new User();
$b = $a->method();
Calling Model Method in any Where the application:
\app\model\ModelName::methodName();
\app\modules\ModuleName\models\ModelName::methodName();
In yii2 you can call a method inside in a model as follows,
$a = Model::method();
Related
I was reading a short tutorial on Laravel here. Since I am not experienced in laravel or development in general I am wondering what this part of the code does exactly:
public function approve(): User
As it is seems to me, it is the same thing as just calling the model from inside the function like so:
App\User::
What is the difference in this two approches?
The first example you shared:
public function approve(): User
is simply a feature of PHP7 which allows you to use static type programming practices with PHP. Essentially this new function signature is telling you that this function needs to return a User type or it will throw a TypeError exception.
The second example you shared:
App\User::
is using what is called the Scope Resolution Operator(::) This operator allows you to call Class Level / Static Methods. In Laravel for example, that would be something like:
App\User::Find(1);
or
App\User::Where('id', 1);
and these differ from object level methods which would be called like so:
$user = new App\User();
$user->id = 1;
$user->save()
Notice the class instance uses the -> operator.
You can learn more about what I mentioned at the following links:
https://secure.php.net/manual/en/functions.returning-values.php#functions.returning-values.type-declaration
http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php
https://laravel.com/docs/5.3/eloquent
Best of luck!
No, they're not the same. The first code is utilizing PHP 7's return type declerations.
It says that the method must return an instance of User class, or PHP will throw a TypeError for you. You can also specify the FQN of the class when defining return type declarations:
public function approve(): \App\User
It's specially useful when defining interfaces:
interface CommentsIterator extends Iterator {
function current(): Comment;
// This enforces that any implementation of current()
// method, must return an instance of Comment class.
}
See what other RFCs made their way into PHP 7:
https://secure.php.net/manual/en/migration70.new-features.php
And treat yourself with Jeffrey's screencasts on PHP 7 new features:
https://laracasts.com/series/php7-up-and-running/episodes/3
But the second code (App\User::whatever()) is just calling the static method whatever() of the App\User class. It has nothing to do with the first code example which enforces return types.
I took clues from DataMapper pattern to create something like this:
class BusinessObjectCreator
{
public function create()
{
//Acquire Data
$number = filter_input(INPUT_POST, "number", FILTER_SANITIZE_INT);
//create and populate object
$object = new Object();
$object->setNumber($number);
return $object;
}
}
//usage:
$objectInstance = (new BusinessObjectCreator())->create();
//examples of usage once created
$objectInstance->someBusinessFunction();
echo $objectInstance->getNumber();
But to me it also looks like a Factory pattern or a Builder pattern.
Which is it? and did I code it up correctly?
Purpose is to create an object instance populated with data. Then I can use the created object to do operations on the data.
This looks like a Factory Method. The naming convention leads you to think it's the builder pattern which has a separate object for the building of the concrete object. You have a separate object but are not setting the data like a builder would.
I'm not too familiar with PHP but to make it a builder pattern you'd create methods for the data, then call create()/build() at the end of the method chain.
It's creation would look like this
$objInstance = (new BusinessObject())->number($number)->create();
Since you only have a class with a method that creates an object, this pattern falls into the factory method category. Usually you use a builder when there are a lot of potential different configurations of an object upon creation, so you may just stick the factory method, if you only are setting one piece of data.
Builder Pattern
I have a Slim application, in the main Middleware I add some generic data to the model
middleware "call" method code
$app->view->set("auths",["user","poweruser"]);
In a controller method I want to push a value to the "auths" array of the view model, is there any way to access it in a faster way than this?:
controller method code
$data=$app->view->get("auths");
$data[]="newauth";
$app->view->set("auths",$data);
In short
No, you can't, but you could define your own view subclass if you want to wrap this functionality nicely.
Native Slim
I just checked out Slim's source code (which is really, really, .. Slim), and you are using its View object which wraps a Set object. Neither supplies this functionality, since the internal array isn't exposed and the all() and getData() methods don't return the internal array by reference, so this won't work:
$view->all()['auths'][] = 'newauth';
You can reach what you want directly with the following nasty one-liner:
$view->set('auths', array_merge($view->get('auths'), ['newauth']));
Roll your own View subclass
Much better would be to define your own custom view that makes this possible!
Define a custom view class
class CustomView extends \Slim\View
{
public function pushProperty($key, $value)
{
$array = $this->get($key);
$array[] = $value;
$this->set($key, $array);
}
}
Note: this method blindly assumes that the current value is an array. You will want to add some checks!
Assign it as the default view object in your Slim app when you create it.
$app = new Slim\Slim(array('view' => new CustomView()));
And start using it :)
$app->view->set("auths",["user","poweruser"]);
$app->view->pushProperty('auths','newauth'); // this will now work. Yay :)
In PHP laravel, we have codes like
$user = User::find(1);
var_dump($user->name);
I am not concerning how to use the find method, I am concerning why laravel use a static method? Shouldn't the use of static method make the method hard to test?
Will it be better if they designed using singleton?
e.g.
$user = User::getInstance()->find(1);
var_dump($user->name);
In fact, your example is very similar to what Laravel does behind the scene. When you do User::find(), you are actually asking for a new instance, either an instance of Collection or a QueryBuilder.
Illuminate\Database\Eloquent\Model (reference):
public static function find($id, $columns = array('*'))
{
if (is_array($id) && empty($id)) return new Collection;
$instance = new static;
return $instance->newQuery()->find($id, $columns);
}
As a side note, you'll also see another way of using static methods in Laravel e.g. Input::get(). These are called Facades.
Facades provide a "static" interface to classes that are available in the application's IoC container ... Laravel "facades" serve as "static proxies" to underlying classes in the IoC container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.
When a user references any static method on the ... facade, Laravel resolves the cache binding from the IoC container and runs the requested method (in this case, get) against that object.
You can read more about Larave's Facades at: http://laravel.com/docs/facades
Unnawut has a very good answer, however I felt it necessary to add in further explanation.
In your example
$user = User::find(1);
var_dump($user->name);
Laravel isn't using a static method, you are. Another way to do this which you are probably looking for is to use dependency injection, which Laravel makes very easy because it can be done automatically. So in whatever class you are using your User model in, you should be setting up something like this in the constructor...
public function __construct(User $user)
{
$this->user = $user;
}
And then you can modify your code to not use the static bindings.
$user = $this->user->find(1);
var_dump($user->name);
This would restrict the system from only having one User. Whilst the find method may be static, the User class will have other methods and properties that aren't, a likely example is in your example: $user->name
A method that does not rely upon any instance variables, I.e variables who's value is specific to the particular object instance, but instead provides generic functionality that applies to all instances, can, and probably should, be static. This is why the $this operator is illegal within static methods, as it can make no reference to a particular object instance.
#unnawut reference link to the source code of Model.php is no longer using static find function as the class has been refactored. The function that get called eventually is in Builder.php (source code),
The logic still same
- magic function `__callStatic` of Model class get called
- a new instance of Builder is created and return
- call the find method of the Builder instance
Model.php
public function newEloquentBuilder($query)
{
return new Builder($query);
}
Builder.php
public function find($id, $columns = ['*'])
{
if (is_array($id) || $id instanceof Arrayable) {
return $this->findMany($id, $columns);
}
return $this->whereKey($id)->first($columns);
}
Just a quick question. I see the following code in an extension and I am not sure what it is doing.
public function actionCreate() {
$model = new User('register'); <----(this is the line I am confused about)
//other stuff...
}
What is the "('register')" doing there? Is it an argument going into the
"User" class? I've looked in the user model, useridentidy, and webuser, and cwebuser classes, but can't find anything. I know that without the proper context, this might be difficult to explain, but in general, what is this extra stuff after the declaration of a new object in Yii? I've been creating objects to use as active records by just typing this:
$model = new User;
(using the "User" class again just as an example)
I'd appreciate any help to clarify this issue.
It's a scenario. Models in Yii can have multiple "scenarios" affecting how validation is performed and which attributes can be assigned in bulk. In this case an object of User class is instantiated with the register scenario, which defines a registration-specific set of validation rules.
$model = new User('register');
This line is for binding the object i.e $model in this case to a scenario which is 'register'.
It is similar to
$model=new User;
$model->scenario='register';
You can set the scenario in this way too. But in order to avoid multiple lines or for the ease of the developers it can be done in this way too :)
Also you can call different scenario in one model:
In your Model rules function:
public function rules(){
return array(
array('username,email', 'required','on'=>'register,update'),
array('firstname,lastname', 'required','on'=>'other scenario here'),
);
}
And where you want to call your custom scenario like in Controller action!
$model = new User('update');
Or
$model = new User('register');
It's an argument being passed to the constructor. Look in the User class for a function called __construct, it will probably accept an argument, and you can see what it is doing.
This is not unique to Yii, any class can accept arguments in it's constructor.