Is there any possible way to lazy load a custom attribute on a Laravel model without loading it every time by using the appends property? I am looking for something akin to way that you can lazy load Eloquent relationships.
For instance, given this accessor method on a model:
public function getFooAttribute(){
return 'bar';
}
I would love to be able to do something like this:
$model = MyModel::all();
$model->loadAttribute('foo');
This question is not the same thing as Add a custom attribute to a Laravel / Eloquent model on load? because that wants to load a custom attribute on every model load - I am looking to lazy load the attribute only when specified.
I suppose I could assign a property to the model instance with the same name as the custom attribute, but this has the performance downside of calling the accessor method twice, might have unintended side effects if that accessor affects class properties, and just feels dirty.
$model = MyModel::all();
$model->foo = $model->foo;
Does anyone have a better way of handling this?
Is this for serialization? You could use the append() method on the Model instance:
$model = MyModel::all();
$model->append('foo');
The append method can also take an array as a parameter.
Something like this should work...
public function loadAttribute($name) {
$method = sprintf('get%sAttribute', ucwords($name));
$this->attributes[$name] = $this->$method();
}
Related
I want to get the a variable of a magento model. In my app/code/community/Project/Module/Model/Module.php, I declare a variable like that :
public var = "image_predefined";
And I want to get this variable from app/design/frontend/product/default/template/product/extension/image.phtml
I can get the model name with mage::getModel($model) where $model contains my model. But I can't get the attribute directly. I tried with ->var or with getAttribute() but it doesn't work.
How should I do to get the variable please ?
You could build your own "getter" for this (depending on context).
Within your model, create the following:
class Namespace_Module_Model_MyModel
{
...
var $image = "image_predefined";
function getImage()
{
return $this->image;
}
...
}
Then you can call your function Mage::getModel($model)->getImage().
Magento will automoatically provide you functionality out of the box (if you're extending the base class) by using magic methods. You just need to make sure you extend the base model provided.
assuming a property called 'my_var' you can use two methods:
$model->getData('my_var');
or (using camel case)
$model->getMyVar();
I want to add an attribute on a pivot table on every attach/save in a belongsToMany relationship.
Example:
// I don't want to do add the `rand` attribute everytime...
User::find(1)->roles()->save($role, ['rand' => rand()]);
User::find(7)->roles()->save($role, ['rand' => rand()]);
User::find(42)->roles()->save($role, ['rand' => rand()]);
// ... I just want to call save...
User::find(1)->roles()->save($role);
// ... and magically, `rand` attribute is set to rand()
I wanted to overload belongsToMany function in Model, but it does not look like to be a good solution, it looks like a hack. Because doing this, I have to create a new BelongsToMany class extending the original one, call the original attach method in Model, then override the returned object, and then my code becomes spaghetti, so I threw everything.
Is there any elegant way to do this?
Side note: rand attribute is a stupid example, it's just an illustration, don't care about it.
create saveRole method in your User model
public function saveRole($role)
{
$this->roles()->save($role, ['rand' => rand()]);
return $this;
}
then just call
User::find(1)->saveRole($role);
I think it's much more easier and clean then overloading BelongsToMany class
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();
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.
I'm trying to optimize my code, and i can't decide on what to use, and whichever is the best practice.
I have a view say view1.php, that is rendered by an action. Now view1 contains a model $model that was passed on to the view by its action; now i'm using the $model again to use it in another different action like below:
view1.php:
$studyDetails = $this->actionStudyDetails($model);
and in the StudyDetails action, i'm going to use the $model,
StudyController.php:
public function actionStudyDetails($model){
//do some processing of the model here and return an object
}
My question is, is it a good idea to pass an entire object that's already been loaded, supposing the model is very large? in terms of optimization , or probably best practice?
or should i just pass the id or primary key say $model->id? and then load the model after; making my action like this:
StudyController.php:
public function actionStudyDetails($id){
$model = $this->loadModel($id);
//do some processing of the model here and return an object
}
Should i pass the entire object unto the action or is it best to just reload the model once inside the action? Thanks, i hope i explained it well
I much prefer loading that single row the database. It's an optimization I wouldn't worry about until it becomes an issue.
You can store the model in your controller to prevent running the same query multiple times:
// Store model to not repeat query.
private $model;
protected function loadModel( $id = null )
{
if($this->model===null)
{
if($id!==null)
$this->model=SomeModel::model()->findByPk($id);
}
return $this->model;
}
It's a trick I learned here.