what is $var means on save($var) on laravel - php

I have a question ,
public function addNote(makenote $note) {
return $this->makenote()->save($note);
}
why there is note var on save method ?
what does it do?

In this case I believe $note refers to the instance of a related model that you want to save.
public function addNote(MakeNote $note) {
return $this->makenote()->save($note);
}
I would assume that on your Model there is a method that looks something like this. This method tell Eloquent that there is a model that is related to your current model.
public function makenote()
{
return $this->hasMany('App\MakeNote');
}
If you do not pass an instance of MakeNote, the $note in this case, there will be nothing to relate to your current model, thus nothing to save.
I'd really go check out the documentation on Laravel also if you want more tutorials Laracasts is a great resource.
Your question is getting down-voted too, because you should include more information about your question and some more examples of your code.

Related

Laravel / Eloquent eager loading

This will be an easy question for some, but I can't seem to find the answer online or in the documentation (only variants of it which I don't want).
Lets say we have a Question class
Each Question object can optionally have multiple Tags
I have set the classes up and things behave as expected. Currently I use:
$questions = Question::all();
This works as expected, however it does not eager load.
To be clear: $question->tags gives the array I am expecting. There is not a relationship problem.
Due to new requirements I will be creating a view with possibly thousands of questions, so this eager loading is a must.
I attempted to use:
$questions = Question::with('tag')->all();
Which gives error message:
BadMethodCallException in Builder.php line 2345: Call to undefined method Illuminate\Database\Query\Builder::all()
Every tutorial, or way I google eager loading, either specifies an ID, OR is a tutorial on how to ONLY show parents with children.
I simple want "all and their children".
This has got to be easy.. does anyone know how to do it?
Thanks
Rick
You should define the method in your model. As far as I see you're going to have one to many relationship. And that's going to be
class Question extends Model
{
public function tags()
{
return $this->hasMany('App\Tag');
}
}
Tag class
class Tag extends Model
{
public function question()
{
return $this->belongsTo('App\Question');
}
}
And the controller. Instead of all() use get() method.
$questions = Question::with('tags')->get();
As I defined tags method in the Question model. Question::with('tags') should call it. Instead, if you're going to do Question::with('tag'), tag method should be defined in Question model.
Notice the s
I've marked both answers as correct: the original syntax suggested is correct, and the class name issue raised was the final issue.
Thanks all:
$questions = Question::with('tags')->get();

Using a query scope in a collection laravel

My Association model looks like this (irrelevant code redacted):
class Association extends Model
{
public function members() {
return $this->hasMany('App\Member');
}
}
My Member model looks like this:
class Member extends Model
{
public function scopeActive($query) {
return $query->where('membership_ended_at', Null);
}
public function scopeInactive($query) {
return $query->whereNotNull('membership_ended_at');
}
}
This is what I want to be able to do:
$association = Association::find(49);
$association->members->active()->count();
Now, I'm aware there's a difference between a Query and a Collection. But what I'm basically asking is if there's some kind of similar scope for collections. Of course, the optimal solution would be to not have to write TWO active methods, but use one for both purposes.
(question already answered in the comments, but might as well write a proper answer)
It is not possible to use a query scope in a Colletion, since query scope is a concept used in Eloquent to add constraints to a database query while Collections are just a collection of things (data, objects, etc).
In your case, what you need to do is to change this line:
$association->members->active()->count();
to:
$association->members()->active()->count();
This works because when we call members as a method, we are getting a QueryBuilder instance, and with that we can start chaining scopes to the query before calling the count method.

PHP coding doubts

I have a code in one of my controller files in laravel, below code is in Teamcontroller.php file:
$faqs = Faq::portal()->get()->toJson();
$glossaries = Glossary::portal()->get()->toJson();
Similarly, we have faq and glossary controller.
I am not able to understand what exactly the above code means. I tried to find function inside the Faq model and Faq controller and glossary model and controller, but i am not able to find any function portal.
Can anyone please explain to me what the above code means and where can I get reference to portal?
Laravel does a lot of magic, in your case it seems to be a Query Scope, from laravel documentation:
Scopes allow you to easily re-use query logic in your models. To define a scope, simply prefix a model method with scope
This is their example:
class User extends Eloquent {
public function scopePopular($query)
{
return $query->where('votes', '>', 100);
}
public function scopeWomen($query)
{
return $query->whereGender('W');
}
}
and it is called as follows:
$users = User::popular()->women()->orderBy('created_at')->get();
So in your case, you should have a method called portalScope in either the given class, or a parent one.
You can read about query scopes here

Override default rest action in Yii2

I created rest api in yii2 for the users. I can access list of users like this "api/web/v1/users" but the problem is that it is giving the data of all the columns including password, I saw in yii2 documentation that it is internally calling "user/index" method, is there any way to override the index method like this?
class UserController extends ActiveController {
public $modelClass = 'common\models\User';
public function actionIndex(){
//return selected columns here of the user table
}
}
It still gives the list of all users with all columns that I don't want. Please help.
In your case, you must use fields() method and override this method. As Yii defines fields():
By overriding [[yii\base\Model::fields()|fields()]] and/or [[yii\base\Model::extraFields()|extraFields()]], you may specify what data, called fields, in the resource can be put into its array representation.You can override fields() to add, remove, rename or redefine fields
For example:
public function fields()
{
return [
'id','name','username'
];
}
Above method, tells yii that only show id,name,username fields. So, Password will never be sent to client.
In cases that you want only remove one or more specific fields, you can do like below:
public function fields()
{
$fields=parent::fields();
unset($fields['password']);
return $fields;
}
While the accepted answer does work and is an important method to know for basic control of what fields are shared via rest and general "object exporting" functions like Json::encode(), I feel it is important to also understand how to completely override an action like the OP references.
I've answered this question here: https://stackoverflow.com/a/50744982/3337682, and I feel it would be helpful, added information for the OP.
Hope this helps someone!
~ Cheers :)

How would you forget cached Eloquent models in Laravel?

Theoretical question on Laravel here.
So Example of the caching I'd do is:
Article::with('comments')->remember(5)->get();
Ideally I'd like to have an event for Article updates that when the ID of a instance of that model (that's already cached) is updated I want to forget that key (even if it's the whole result of the query that's forgotten instead of just that one model instance), it is possible to do so?
If not is there some way to implement this reasonably cleanly?
So i was looking for an answer to the same question as OP but was not really satisfied with the solutions. So i started playing around with this recently and going through the source code of the framework, I found out that the remember() method accepts second param called key and for some reason it has not been documented on their site (Or did i miss that?).
Now good thing about this is that, The database builder uses the same cache driver which is configured under app/config/cache.php Or should i say the same cache system that has been documented here - Cache. So if you pass min and key to remember(), you can use the same key to clear the cache using Cache::forget() method and in fact, you can pretty much use all the Cache methods listed on the official site, like Cache::get(), Cache::add(), Cache::put(), etc. But i don't recommend you to use those other methods unless you know what you're doing.
Here's an example for you and others to understand what i mean.
Article::with('comments')->remember(5, 'article_comments')->get();
Now the above query result will be cached and will be associated with the article_comments key which can then be used to clear it anytime (In my case, I do it when i update).
So now if i want to clear that cache regardless of how much time it remembers for. I can just do it by calling Cache::forget('article_comments'); and it should work just as expected.
Hope this helps everyone :)
I think a good way to do is like this:
$value = Cache::remember('users', $minutes, function()
{
return DB::table('users')->get();
});
and then use Model Observers to detect the event of updating the model
class UserObserver {
public function saving($model)
{
//
}
public function saved($model)
{
// forget from cache
Cache::forget('users');
}
}
User::observe(new UserObserver);
Currently there are no easy way. However I found this workaround, which so far worked for me.
First you have to extend Illuminate\Database\Query\Builder.
<?php
class ModifiedBuilder extends Illuminate\Database\Query\Builder {
protected $forgetRequested = false;
public function forget()
{
$this->forgetRequested = true;
}
public function getCached($columns = array('*'))
{
if (is_null($this->columns)) $this->columns = $columns;
list($key, $minutes) = $this->getCacheInfo();
// If the query is requested ot be cached, we will cache it using a unique key
// for this database connection and query statement, including the bindings
// that are used on this query, providing great convenience when caching.
$cache = $this->connection->getCacheManager();
$callback = $this->getCacheCallback($columns);
if($this->forgetRequested) {
$cache->forget($key);
$this->forgetRequested = false;
}
return $cache->remember($key, $minutes, $callback);
}
}
Then you have to create new class which extends Eloquent Model.
<?php
class BaseModel extends Eloquent {
protected function newBaseQueryBuilder() {
$conn = $this->getConnection();
$grammar = $conn->getQueryGrammar();
return new ModifiedBuilder($conn, $grammar, $conn->getPostProcessor());
}
}
Now when creating Eloquent Models, instead of extending Eloquent Models extend newly created BaseModel.
Now you can remember query result as usual.
YourModel::remember(10)->get();
When you want to discard the cached result all you have to do is
YourModel::forget()->get();
If you remember the result previously, after clearing the cached result, model will continue to remember the result for that amount of time.
Hope this helps.
I was testing for debug mode. So I found that if you put a test for app.debug in a constructor you are able to clear the cache associated with a key. Saves you having to duplicate the code for every function.
class Events {
public function __construct() {
if (\Config::get('app.debug')) {
Cache::forget('events');
}
}
public static function all() {
$events = \DB::table('events as e')
->select('e.*')
->where('enabled', 1)
->remember(30, 'events')
->get();
return $events;
}
}

Categories