Here is an example of what I am trying to do (I have PRO version and DevTools incase anyone needed to know):
Lets say I have a CRUD setup for People.
In the List I have the School the Person is assigned to.
In the People CRUD I want to be able to Search for a "Name" of the School the person goes to but when selected and saved the CRUD will just store the School ID associated so its a relation.
Then on the list view it will showcase the School Name but again in the database only stores the ID and goes and fetches the Name. I am sure this is really easy to do but I cannot seem to find documentation on this as an example.
I have checked the docs and good as best as I can but not been able to find any documentation on it so any info or links would be great!
In your People model you should have the relationship setup like:
public function school()
{
return $this->belongsTo('App\Models\YourSchoolModel', 'school_id');
}
So you should define your columns like:
public function setupListOperation()
{
$this->crud->addColumn([
'name' => 'school',
'searchLogic' => function ($query, $column, $searchTerm) {
$possibleSchools = SchoolModel::where('school_name', 'LIKE', '%'.$searchTerm.'%')->pluck('id');
return $query->orWhereIn('school_id', $possibleSchools);
},
]);
You can check other examples here: https://backpackforlaravel.com/docs/5.x/crud-columns#custom-order-logic-for-columns
Cheers
Related
In my app users can vote on submissions.
I first run a delete query for that submission to prevent any duplicate votes, then I save the vote:
SubmissionVote::where('submission_id', $submission->id)->where('user_id', Auth::user()->id)->delete();
$submissionVote = new SubmissionVote;
$submissionVote->submission_id = $submission->id;
$submissionVote->user_id = Auth::user()->id;
$submissionVote->vote = $vote;
$submissionVote->save();
Would it be possible to write this as one query to minimize overall database queries?
Or perhaps there's a way in the table migration to make it so that every submission_id can only have unique user_ids?
You could do this in a neater way like so:
Create a proper relation on the User model:
// models/User.php
public function submissionVote()
{
return $this->belongsTo(SubmissionVote::class);
}
then simply use this single statement in your controller:
Auth::user()->submissionVote()->updateOrCreate([
'vote' => $vote,
]);
This automatically updates the current user's submission OR creates a new one if it doesnt exist yet. Note that you have to use ->submissionVote() (query instance) vs ->submissionVote (model instance) so that you can use the query functions like updateOrCreate(). There are others available like firstOrCreate() or firstOrNew() which do slightly different things but are extremely handy shortcuts.
See https://laravel.com/docs/8.x/eloquent#upserts for more information.
Yes, it perhaps.
Schema::create('submission_votes', function (Blueprint $table) {
$table->unique([
'submission_id',
'user_id',
]);
});
And, update existing model:
SubmissionVote::query()->updateOrInsert(
['user_id' => Auth::user()->id, 'submission_id' => $submission->id],
['vote' => $vote]
);
Based on the official Laravel documentation I found that :
$books = App\Book::with('author.contacts')->get();
In this case, imagine we have a structure like this :
books
books_authors
authors
contacts
books_authors_contacts
That's just an hypotetic case but I would like some more information : what about if I would like to retrieve all authors contacts for this specific book, imagining that for a specific book multiples authors could have multiple contacts (such contacts are linked through both authors and books as the entity books_authors_contacts says)
Is it possible to retrieve it through Laravel with eager loading with a belongsToMany relation?
By using the example below, it would just retrieve all of the contacts of an author no matter the book is.
Thanks you in advance!
There is tricks to gain this functionality in a very complex fashion, see this post. In a more practical sense, when these cases arrive in a professional environment, you often end up doing a method that aggregates this data. This can be done in multiple ways, this is an approach i feel is fairly easy and readable.
public class Book
{
public function contacts()
{
$contacts = new Collection();
$this->authors->each(function(Author $author) use($contacts) {
$contacts->concat($author->contacts);
})
return $contacts;
}
}
Offcourse for the eager loading, you have to remember to include the whole structure. For more Laravel approach contacts can be made as a Eloquent Mutator.
$book = App\Book::with('authors.contacts')->find(1);
$contacts = $book->authors();
I am looking for some way to implement the following thing with yii2:
Lets imagine we have the following structure:
- authors table.
- Books table
Each author -> has written 1 or more books.
What I want to do is to display on a view, the details of an author, and under it, a gridview of all the books it has written. After that, control buttons to create/ remove new books for that current author, along with a gridview of the books which belongs to the current author... In some other words, a master-detail view.
How I should retrieve the data of the books? From the same controller for Authors?
I have already implemented the table relations between authors and books, in the Author's model
Thanks in advance, any help is welcome!!
If the you have the following relation in your Author model:
public function getBooks()
{
return $this->hasMany(Books::className(), ['author_id' => 'id']);
}
After declaring relations, getting relational data is as easy as accessing a component property that is defined by the corresponding getter method:
$author = Author::findOne(1);
$books = $author->books;
http://www.yiiframework.com/doc-2.0/guide-db-active-record.html
The solution I found at the end was to :
On the Author's controller, I modified the "view" action, so I could a "books" activeDataprovider, and then filtering it by "author id":
public function actionView($id)
{
//get current author
$author=$this->findModel($id);
$books_search = new BookSearch();
//get the related books for current author
$written_books = $books_search->search(['bookSearch'=>['id_author'=>$id]]);
return $this->render('view', [
'author' => $author,
'books_search'=> $books_search,
'books'=>$written_books,
]);
}
Then I could create on the Author's view, a gridview with the books written by the current author
I have the following setup:
Clubs offer Activities, which are of a particular Type, so 3 models with relationships:
Club:
function activities()
{
return $this->hasMany('Activity');
}
Activity:
function club()
{
return $this->belongsTo('Club');
}
function activityType()
{
return $this->hasMany('ActivityType');
}
ActivityType:
function activities()
{
return $this->belongsToMany('Activity');
}
So for example Club Foo might have a single Activity called 'Triathlon' and that Activity has ActivityTypes 'Swimming', 'Running', and 'Cycling'.
This is all fair enough but I need to show a list of ActivityTypes on the Club page - basically just a list. So I need to get the ActivityTypes of all the related Activities.
I can do that like so from a controller method that receives an instance of the Club model:
$data = $this->club->with(array('activities', 'activities.activityTypes'))->find($club->id)
That gets me an object with all the related Activities along with the ActivityTypes related to them. Also fair enough. But I need to apply some more filtering. An Activity might not be in the right status (it could be in the DB as a draft entry or expired), so I need to be able to only get the ActivityTypes of the Activities that are live and in the future.
At this point I'm lost... does anybody have any suggestions for handling this use case?
Thanks
To filter, you can use where() as in the fluent DB queries:
$data = Club::with(array('activities' => function($query)
{
$query->where('activity_start', '>', DB::raw('current_time'));
}))->activityType()->get();
The example which served as inspiration for this is in the laravel docs, check the end of this section: http://laravel.com/docs/eloquent#eager-loading
(the code's not tested, and I've taken some liberties with the property names! :) )
I think if you first constraint your relationship of activities, the activity types related to them will be automatically constrained as well.
So what I would do is
function activities()
{
return $this->belongsToMany('Activity')->where('status', '=', 'active');
}
and then your
$data = $this->club->with(array('activities', 'activities.activityTypes'))->find($club->id)`
query will be working as you would expect.
In doctrine, is it possible to add a WHERE clause when fetching a property of an object that corresponds to a relationship?
In terms of concept, let's say I want to retrieve only the first 3 blog posts made in the last 5 days. My "blog" object has a "posts" property which is defined as a relationship.
Update...
As some people are having some difficulties understanding what I mean by a relationship:
class Blog extends Doctrine_Record {
...
public function setUp() {
$this->hasMany("Note as Posts", array(
"local" => "blog_name",
"foreign" => "post_id",
"refClass" => "BlogPost"
));
}
}
As you can see, this is an explicit relationship as supported by doctrine. When I query using it:
$instanceOfBlog->Posts...........
I'd like to know if I can add additional clauses at that time.
Not sure I follow you, but if it's what I think then in your BlogTable class:
public function getRecentPosts()
{
$qry = self::createQuery("b")
->innerJoin("b.Posts p")
->where("p.created_at > ?", date("Y-m-d H:i:s", strtotime("-5 days")))
->orderBy("p.created_at DESC")
->limit(3);
$results = $qry->execute();
}
Is that what you were after? This is based on the created_at field in the Posts object, and assumes a relationship is defined between the Blog and Posts tables.
I may have misunderstood your question entirely however :-)