Display parent-child relation yii2 - view

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

Related

BackPack CRUD Select Title But Save ID

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

Laravel relationships (one to many)

I am new to Laravel and maybe somebody can give me an example for this.
I have two tables - Auhors and Books and two views - authors.index and books.index.
I know how to display all the books related to author in authors.index, but the question is, how to display all authors related books in books.index view?
My models and BookController:
Authors
Books
BooksController
You need to use the opposite function belongsTo into your Books model.
public function authors() {
return $this->belongsTo(Authors::class, 'author_id', 'id');
}
You can find more info here

Laravel 3 tables on belongsToMany relation

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();

Cant access relations in 'created' Model Event?

Could someone please clarify this? I've used Model Events a lot of times before but it seems I haven't tried to access any related models on the initial "created" Event.
For example, I have two Models in a M2M relation to each other:
Book() public function authors()
Author() public function books()
I have saved a new Book object, with related authors, elsewhere in my code and by tapping into the "created" or "saved" Model Event (in EventServiceProvider.php), I would like to be able to update some fields in the related objects at the same time like this:
Book::created(function($book) {
$authors = $book->authors;
foreach($authors as $a){
$a->books_authored += 1;
$a->save();
}
});
..but I can't, as $authors call returns no related objects. If this is the usual behaviour (and I haven't done something incorrect here)? Is there a way to get access to these relations on the initial creation/saving Event?
Thanks in advance.
I think the problem you are having is that the created event is firing before you have attached the authors. You haven't attached your code, but I'm assuming:
Book::create(['title' => 'Foo'])->author()->save(new Author['name' => 'Brian']);
This is actually the following:
$book = Book::create(['title' => 'Foo']) // Book created event fired
$relation = $book->author(); // Relation retrieved
$relation->save(new Author['name' => 'Brian']); //related author attached
You should probably manually fire an event when you attach an author in a function on your book model e.g.
class Book extends Eloquent
{
public function saveAuthor($author) {
if($this->save($author)) {
Event::fire(new AuthorWasAttached($this, $author));
}
}
}
Then do your processing in the AuthorWasAttached event class
This may be of help.
You create the book object and then;
$author=new Author(['name'=>'Joo']);
$book->authors()->save($author);

condition for model anytime I refer to it yii

I have model Post and Article which is inherited by Post. Table tbl_post contains text records (title, text, type) where type may be:
1 - article (model Article)
2 - news (model News)
etc.
I want model Article to return only records where type=1 (for example) whenever I refer to it.
How can I do this?
Thank you.
You can use the defaultScope-function in the Article model:
public function defaultScope()
{
return array
(
'condition' => 'type = 1'
);
}
That is the easiest way I can think of. You can then just do Article::model()->findAll() or something like that and it should only return articles.

Resources