laravel one to many record insert and update solution - php

I have two tables one is "ITEM" and second one is "Composite Item" in mysql database. I am trying to insert multiple items id in composite item table for one single record in laravel.
One of logic I have tried to save multiple items id as comma separated value for example "1,2,3,4" and also update that one field as same concept. but I am having issue when i delete any one item from item table. if i delete any of the item from item table how can i delete that same item from string item ids in composite item table. for example from item table i have deleted item id 3.
also i have think if i create new table for one to many relation then how can i update record when i update record.

You are definitely looking for many-to-many relationships, not one-to-many. Laravel has excellent features for generating and maintaining a many-to-many relationship.
The attach/detach methods are used for single or multiple insertion or deletion in a relation. For example, if you want to add an array of items([1,2]) to a composite item, you can use attach like:
$compositeItem->items()->attach([1,2]);
Same goes for detaching:
$compositeItem->items()->detach([1,2]);
The sync method is used for updating existing records.
Sync is a bit tricky and work exactly like:
The sync method accepts an array of IDs to place on the intermediate
table. Any IDs that are not in the given array will be removed from
the intermediate table.
Like if you want to remove 2 and insert 3 you can use sync like this:
$compositeItem->items()->sync([1,3]);

Related

How to stop auto sorting in laravel pivot table of many to many realtion

I have a author table and a publication table. Both are related to each other in a many to many relation. When I'm inserting the publications the authors of the publications are inserted in the pivot table by the order of authors id. But I need to insert it by the order i'm selecting the authors in the front-end. Whatever the order of the authors in the front end is it is getting ordered by the author's id in the pivot table. How can i stop this automatic ordering
You can't add rows in a specific order into a pivot table, because it doesn't really make sense.
Let's consider an users table:
The first user you enter will have the id 1
The second will be assigned to the id 2
And so on...
So you can enter the users in a specific order and retrieve them by their id.
However, in a standard pivot table, the primary key is composed by two columns, in your case the author_id and publication_id. Nothing new is created here, you just associate the primary key of two existing rows in two differents tables in order to achieve one - and unique - composed primary key.
If i explained well (and i hope so :p), you should understand why saying
But I need to insert it by the order i'm selecting the authors in the front-end.
doesn't really make sense.
But, don't worry, it is still possible to achieve your goal here.
Instead of using a pivot table, you can use a normal table with an id. This way, the order of insertion will be preserved. It will work but that's not very nice.
A better approach would be to add an additional column to the pivot table. A column like position. This column could be incremented for each author you insert. Then, you can order the table by the position column, by simply adding ->orderBy('position') to your relationship or every queries that needs to.
Here is an example to illustrate what i said above:
foreach($authors as $position => $author)
{
$publication->authors()->attach($author, ['position' => $position]);
}
If $authors contains the authors in the order you selected them on the front-end, they will be added accordingly.
If you need to sync instead of attach, that's also possible, it's just a little bit more verbose:
$syncData = $authors->mapWithKeys(function($author, $position){
return [$author->id => ['position' => $position]];
});
$publication->authors()->sync($syncData);
Don't forget that you can add false as a second parameter on the sync method so it'll only add new authors.
After that, just change your authors relationship in your Publication model like this:
public function authors(){
return $this->belongsToMany(Author::class)->orderBy('position');
}
Or everywhere you need to:
$publication->authors()->orderBy('position')->get();
I hope it helps !

MySQL Multiple tables or multiple values for single field?

This is a problem I've had for a while and not sure what is the best way to solve it.
Its probably easier for me to explain using an example.
So I have many collections and many items. Some items can belong to one or more collections or none at all. Collections must have at least one item but there is no limit to the number of items that it can have.
How do I store this information in a MySQL database / what is the most efficient way of doing it?
I already have a table of items with a unique ID per item, thats the easy part, creating the collections part is where I'm stuck.
Do I create a new table for every collection, give it a unique table name and insert new records for each item that belongs in that collection?
Do I create just one large collection table with each record being a new collection and a single field of all the item ids?
Is there another way of doing it?
This will be queried using a php site if that makes any difference to the database structure.
I think you should..
Create a collection table with all collections, an item table with all items, and a collection-item map table which will have id(primary key), collection_id (foreign key to collection table), item_id(foreign key to item table). This table will represent the relation between a collection and item. It can have any number of collection item relation.
Hope this helps.

¿How to avoid record from a table in pagination if this record is not present in another related table? CAKEPHP

I have a doubt doing pagination in CakePHP.
Well, I will try to be concise.
I have three tables, one table is which I paginate (1st table), another table (2nd table) dependent of this one (1st table have FK to 2nd table), and the most important, 3rd table, that has FK to 1st table. So: 3rd table-> 1st table-> 2nd table.
I do pagination of 1st table (model) from his controller, so far everything ok, the pagination list all the records from table bd and no problems.
I need also to get records from 1st table but ordering by a record from 2nd table. No problem. The problem IS: I WANT not to get in pagination, records from 1st table (which i paginate it) that arent present in 3rd table.
The problem is that CAKEPHP first make a query getting records from 1st table + 2nd table. After this, it get the records from 3rd table according to the records (PK) obtained from the first query, so I cant say it: not take records from 1st table that arent present in 3rd table.
¿How can I do this?
I hope I explained.
Thank you very much.
Regards.
what you'll want to use is a Counter Cache. Go to http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html and search for 'counterCache,' and you'll find instructions.
Basically, you want to implement a "counter cache" field in model 1, that automatically keeps count of the number of linked records in model 3. Then, to exclude records from Model 1 that have no related records in Model 3, you just add a pagination condition to say that the counter cache field must be greater than 0.
UPDATE:
If you can't use CakePHP's counter cache, then you should emulate the behaviour of the counter cache using a virtual field - see http://book.cakephp.org/2.0/en/models/virtual-fields.html

Laravel 4 Many to Many update

I'm stuck in a problem and I can't find a solution to this, it's annoying me.
I've two tables, one called contacts and the other one called phonebooks and they are linked with a third table called *contacts_phonebooks*, this is a many-to-many relationship summarize below:
contacts: id (pk)
phonebooks: id (pk)
contacts_phonebooks: contactid (fk), phonebooksid (fk)
Pretty simple and clear, and it works.
I'm using Laravel 4 and Eloquent ORM, everythings works fine when I've to fetch it, insert it and delete it but when I need to update a contact I fail miserably. I've a form that has a number of checkboxes that represent all the phonebooks (every checkbox has phonebook[] as name) so when you check one of those the phonebook id will be saved in the *contacts_phonebooks* with the contact id.
The problem is that this is not true! I mean when I run this code:
$contact = Contact::find($id);
$contact->contact_name = Input::get('newCName');
$contact->contact_surname = Input::get('newCSurname');
$contact->contact_email = Input::get('newCEmail');
$contact->contact_phone = Input::get('newCPhone');
$contact->contact_birth = Input::get('newCDate');
$contact->phonebooks()->sync(Input::get('phonebook'));
if($contact->save())
{
return "TEST DONE?";
}
It deletes every row in *contacts_phonebooks* associated with the contact id and save only the new one checked... This is weird I know, I try to explain it better.
I want to update Mr.x and he actually is in "Stackoverflow" phonebook, I want to add him in "Nerd" phonebook so I click on update and I selected "Nerd", the other one is already selected.
When I update him the system deletes the "Stackoverflow" link and save ONLY the "Nerd" phonebook (with the code above) this things driving me crazy because Laravel 4 Doc says that you should use the sync() method in order to update a many-to-many relationship.
I don't how how to solve it, I hope you will understand what's my problem.
Cheers.
The documentation says "The sync method accepts an array of IDs to place on the pivot table. After this operation is complete, only the IDs in the array will be on the intermediate table for the model:"
So what I think you are probably looking for is attach().
$contact->phonebooks()->attach(Input::get('phonebook'));
Then you will have to use detach() to remove him from the other.
As stated in the docs: The sync method accepts an array of IDs to place on the pivot table.
Your pivot table should be named
contact_phonebook
and it specifies that in Laravel's documentation.

Should I split the mySQL tables?

Lets take the example from Yelp: http://www.yelp.com/boston
You can see that it's a website with several different categories, each category containing a listing of places. Should I include all the different places/listing in a single table, or let each category have its own tables?
EDIT: this means having tables 'places_restaurants' and 'places_nightlife', instead of just having the single table 'places' and every entry of every different category will be stored in one huge table... Will this affect performance?
One table per category will require that you CREATE a table every time there's a new category. I'd prefer CATEGORY and PLACE tables, with a one-to-many or many-to-many relationship between them.
You should keep all of the categories in the same table and then have a CategoryID which actually maps each category to the specific / desired category. Your application should be built in a way that is inherently extensible which creating tables each time is definitely not.
It depends. You could normalize the database so that all categories are in their own table, and only referred to from other tables by a foreign key. But there are some arguments that performance outweighs normalization, and so it may be beneficial to keep category names both in their own table of record, and also to include a category name column in other, frequently-joined tables.
If you took the second approach, you would need to ensure data integrity by implementing UPDATE and DELETE triggers such that whenever a category changes in the table of record (presumably, not often), that other tables containing copies of category names also get updated.
It still depends on the application ,also, all the categories is a many to many fields with a main table and of course beliving u have some unique columns in each table

Categories