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();
Related
I'm trying to get a custom constructor to work with a model extending an Eloquent model in Laravel 5.4
I already make sure to call the parent constructor, but it seems that nothing that I do takes any effect at all after that.
Here is my __construct function:
public function __construct(array $attributes = [])
{
parent::__construct($attributes);
$this->users();
}
And here is the users() method:
public function users()
{
$this->users = collect();
foreach($this->employees as $employee) {
$this->users = $this->users->push($employee->user);
}
$this->users = $this->users->unique();
}
In this example employee is a class that links a user to a store and also defines their jobs. However, it doesn't matter what I try to assign. I have also tried just assigning a garbage variable in the constructor with
$this->foo = 'bar';
or even trying to overwrite an attribute, such as
$this->name = 'foobar';
to no avail. I've also tried to simply switch the order of the code calling parent::__construct() before or after my code and nothing at all changes.
Any help would be greatly appreciated!
If changes in your child class are not showing up, even when you load garbage into it, it sounds like it to me that you might not be loading the right class into the context?
Perhaps check your use statements at the top to make sure you loaded the child class and not the parent. It would be easy not to notice, since they share the same interface, no syntax error would be called inherently.
If that's all OK, then I would check the logs for anything suspicious (e.g. error messages related to the function).
As well, it's very useful to use the dd() function along the execution chain to see the type and contents of your variables. You may find it being overridden at some unexpected point.
So, I'm an idiot, basically. The constructor functionality was working perfectly. My problem was I was trying to set attributes not on a new instance of a class, but after retrieving it, which worked out better by just using the getAttribute methods.
Thank you everyone for trying to help, but it was just me being dumb.
I changed, by client requirement, an entity textfield (weekly_exercise) to a 1:n relation. Everything works normally so far, but when trying to save the form Symfony looks out for a "changed" method name.
That's the error message I get
Neither the property "weekly_exercise" nor one of the methods "addWooklyExercise()"/"removeWooklyExercise()", "setWeeklyExercise()", "weeklyExercise()", "__set()" or "__call()" exist and have public access in class "XXX\CourseBundle\Entity\Course".
Of course "addWooklyExercise()"/"removeWooklyExercise()" don't exist. I could put them in and proxy to the real methods, but that would only be an ugly hack.
I've been looking through all my files and couldn't find a anything that could be responsible for this issue.
I'm on Symfony 2.5.7 as my client doesn't allow me to update!!
Files involved in the issue https://gist.github.com/mhauptma73
EDIT:
For some reason the method
public function addWooklyExercise(\BDA\CourseBundle\Entity\CourseWeeklyExercise $weeklyExercise)
{
$this->__initializer__ && $this->__initializer__->__invoke($this, 'addWooklyExercise', array($weeklyExercise));
return parent::addWooklyExercise($weeklyExercise);
}
is being added in the cache proxy. But there is also the correctly spelled method, before the misspelled one.
Follow the naming convention like when you add the property for oneToMany then it's plural and for add or remove method change it to singular.
protected $tags;
public function addTag(Tag $tag)
{
//...
}
public function removeTag(Tag $tag)
{
// ...
}
See more details read this doc:
http://symfony.com/doc/2.7/form/form_collections.html#form-collections-new-prototype
That looks like you have a typo somewhere, probably your Entity, your Form-Type or when outputting a form in a template. Try doing a search over the whole src/ directory for wookly and you will probably find it.
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.
If I have a model that needs to have a property that is an array of different models. Is there an eloquent method or way to handle this kind of problem?
eg.
I have a Feature model that needs a method that gets an array of objects that are from different models.
class Feature extends Model
{
public function getArrayOfDifferentObjects()
{
$array_of_objects=array();
???? ELOQUENT to get objects from different models ????
return $array_of_objects;
}
}
I have a feature_model_connections table with the following:
feature_id
featured_model_id
featured_model_type
The featured_model_type value would be a string denoting the model type.
The model_id would be a foreign key of the relevant model's table.
However I can't see how you would be able to use eloquent to return data for the getArrayOfDifferentObjects method in features model.
Any pointers would be much appreciated. Many thanks, J
What you are describing there, is basicly a Polymorphic Relations, which can handle these cases, and making fetching them easy, instead of i'm making a made up case, read the documentation, it is well written, under the section Polymorphic Relations. https://laravel.com/docs/5.1/eloquent-relationships#polymorphic-relations
Within your scope right now, you can do something like this.
public function getArrayOfDifferentObjects()
{
$objects = [];
$features = DB::table('feature_model_connections')
->select('feature_id', 'featured_model_id', 'featured_model_type')->get();
foreach($features as $feature)
{
$type = '\\App\\' . $feature->featured_model_type; //App is you app namespace
$model = $type::find($feature->featured_model_id);
if($model)
$objects[] = $model;
}
return $objects;
}
The basics of this, is you can define different types, with the app namespace seed, from there staticly call them, which will access the predefined type in your database table, then find the element and add it to the array. With that said, this is done as of the top of my head, no compile check, not ranned in Laravel, but it should pretty much get you the idea of what to do, with that said, if you can change your structure, go with the Polymorphic Relations, it is really awesome.
I am trying to merge two websites created using Laravel 5 into one multisite (yes, I wasn't that experienced when making that decision). The two websites are one for cats and one for dogs.
My problem is that I have a model called Item, the one in cats is storing things in a different table than model Item in dogs.
What I have done in my controller:
protected $posts_class;
public function __construct()
{
$this->items_class = "App\\Models\\" . config('domain') . "\\Item";
}
public function index()
{
$items = $this->items_class::all();
return view('items')->with('items', $items);
}
but it keeps giving an error:
syntax error, unexpected '::' (T_PAAMAYIM_NEKUDOTAYIM)
however if I do:
public function index()
{
$class= $this->items_class;
$items = $class::all();
}
it works.. but I don't want extra variables within the controller method.
I would like to know why the first one doesn't work. If anyone has any recommendations on how to make this multisite work in a better way than this one then I am open to suggestions. Thank you.
The T_PAAMAYIM_NEKUDOTAYIM operator is more commonly known as the Scope Resolution Operator. In the context of PHP, it is used to statically access class methods and variables.
The all() method is a static method on the Eloquent class your model inherits from. As such, it should be called like ClassName::all().
If I understand what you are trying to do correctly, you are trying to use a dynamic variable as the class name. Unfortunately, using $this->someVariable::all() doesn't quite work the way one would expect like that, and as you know, you have to separate it into an individual variable first.
In the spirit of answering your question directly with a way to call it without creating a separate variable, the answer is to use the often forgotten forward_static_call method.
$items = forward_static_call([$this->items_class, 'all']);
If you need to call a static method using this methodology and want to pass an array of parameters, there is also a related function forward_static_call_array().
Reference:
http://php.net/manual/en/language.oop5.paamayim-nekudotayim.php
http://php.net/manual/en/function.forward-static-call.php
http://php.net/manual/en/function.forward-static-call-array.php