Insert model unless it exists and attach it - php

I'm a Laravel noob rewriting some old code to Laravel.
I have a system for managing purchases and games and I'm writing the store method of the PurchaseController. The form for creating new purchases contains data about the purchase and an array with data about the games.
There is a many-to-many relationship between games and purchases: a purchase can contain many games and a game may be linked to multiple purchases.
The thing is that the game may already exist in the database. I want to do the following:
Insert the new purchase into the database (this part I got sorted out already ;))
Check if the POSTed name of the game already exists in the database.
If it exists, attach it to the newly inserted purchase. If it doesn't exist, insert it and attach it to the newly inserted purchase.
I don't want to update the game if it already exists in the database, just to attach it to the purchase.
I've looked into firstOrCreate but that doesn't do what I want. It checks on all the arguments you feed it, you can't just make it check only the name (this issue basically).
The undocumented method updateOrCreate does accept two arrays (one for attributes to check on, another for values to insert) but it updates the record if it exists, which is not what I want.
So, is there a nice, proper way to do this with Eloquent or do I simply need to manually write some code that checks if the game exists in the database and inserts the game unless that's the case?
EDIT:
It seems that this is possible with firstOrCreate after all in Laravel 5.3: https://github.com/laravel/framework/pull/13236

firstOrCreate is what you need, but you can feed it just the game name, then attach it to your purchase.
$game = Game::firstOrCreate(['name' => $gameName]);
$purchase = new Purchase(['otherArgs' => ...]);
$purchase->games()->attach($game);

I was probably overthinking this too much. The following code does what I want:
// Insert games (unless they exist) and attach to new purchase
foreach($request->games as $game) {
$gameModel = Game::firstOrNew(['name' => $game['name']]);
if(!$gameModel->exists) {
$gameModel->status_id = $game['status'];
$gameModel->note = $game['note'];
$gameModel->save();
}
$gameModel->purchases()->attach($purchase->id);
}
I just thought maybe there was a nicer/shorter way to do this.

Related

How do I make a notification table that makes eloquent relationships to other tables without making too many "<source>_id" columns

Suppose that I have a Notification Table that gets generated when a new log from another table is generated. Suppose I have 3 different logs with different purpose namely: sms_logs, call_logs, and appointment_logs.
I want to make a relationship to each logs without using sms_logs_id, call_logs_id and appointment_logs_id. Instead, I want to build only two columns, one for the type, and the other for the ID. So for example an sms log is generated with an id of 187, it will also generate a notification log with a notification_id of 187 and a type of "sms".
How will I be able to create that? Thank you!
Nice question.
You have to put only two fields in notifications table. foreign_id and log_type.
Whenever you add a log, you have to set log_type accordingly. Then add this relationship in your Notification model.
public function foreignModel()
{
switch($this->log_type){
case "call_log":
return $this->belongsTo('App\Call', 'foreign_id');
break;
}
}
I didn't tried it, but hope it will work fine.
If you are looking for something more dynamic and less robust than this then I don't think that it exists.

Database set up for multi-way relationships and form data collecting

I've posted a few questions on here and have gotten very great help and support. I'm still fairly new to programming and I'm putting together what I thought would be a simple website for the company I work at. I apologize in advance for my lengthy post/question, I just want to be thorough and clear in what I'm asking. My question is more of needing some help getting pointed in the right direction of how to get started and some best practices to be aware of. What I'm working on right now is to create a system where a user can submit a questionnaire/online form to inquire about a specific product (in this case it's a hard money loan product). The way I am planning on setting it up is to have a database with multiple tables (users, user_info, loan_app, property) and connect these together by referencing each other. I've read about table joins and I understand them conceptually but I have no idea how to implement in practice. I've had a hard time finding actual examples.
Specifically, this is what I am doing and how I am thinking it should work (correct me if I'm wrong or if there's a better way to do it):
1- the user (aka the borrower) signs in to the website. The user log in system references the user table where things like first name, last name, user name, password and user ID are stored. I have included an "active" column in this table so that when a user logs in the condition for them to get into the website is that the username and password match AND the user is activated. This way we can control on the back end certain user accounts access. I have this part working.
2- when the user registers, they only fill out the information that creates a new record in the "user" table. I have created a second table called "user_info" that will contain other data like home address, phone number email etc. But I need to be able to associate the correct record with right user. This is my first issue to wrap my head around. My thinking behind doing this instead of simply putting all this information in the user table is that for one, I might keep adding to that table and make it very big, and two for security reasons, I would like to keep the information separate. I don't know if this thought process has any merit to it though. Again, that's why I'm posting this here.
3- The user, once logged in, clicks on a button on their home screen/dashboard that will take them to the loan "pre-approval application" form, which is the questionnaire. On this form their basic information will be echoed/posted from the "user_info" table to pre-populate certain fields like first name, last name, email, phone number, address etc. So going back to #2 making sure I can associate the user with the correct record in the "user_info" table is critical. THEN, there are additional fields that the user has to fill out in order to submit the application/questionnaire. These form fields will create a new record in the "loan_app" table. This table will have a loanid column that is the primary key for that table, and an auto generated/randomized 6 or 7 digit loan number (loannum). The loanid will be a hidden value but the loan number will be like a reference number that is associated with the loan for the life of it and used for later accounting and recording purposes internally, whether or not it actually becomes a loan. The loanid, I'm assuming here, is the Foreign key in the "user" table and the userid is the Foreign key in the "loan_app" and "user_info" tables correct? If so, how do I incorporate being able to simultaneously associate all these records when the loan application/questionnaire is submitted? My thought would be write individual php scripts that does each of these things separately then have a "master" php that includes all of those individual ones that is placed as the form action associated with the submit button on the form.
Thanks for taking the time to read through this. I'd really appreciate any advice or reference material that I can read up on to learn more about this stuff. My job has a pretty crazy schedule and I travel a lot so I don't have the time to take actual classes to learn this stuff formally. I'm pretty much doing this as I go.
Also, I'm using MAMP with mysql, not sure if that helps any or not...
The user table's primary key userid can be the primary key of the user_info table as well, since each user will have only one user_info record, right? A foreign key constraint is good to ensure only valid userids get recorded in user_info.
The loan_app table can contain a denormalized relationship from loanid to userid so that each loan application is associated with a user. Again, use an FK constraint for integrity.
Don't include loanid in the user table - that would mean each user has a relationship to a single loan application. You already have the one-to-many relationship you need in the loan_app table.

Symfony2: is ArrayCollection better than multiple db queries?

In Symfony2 I have two entities (Companies and Employees) with a One-to-Many relation (one company can have multiple employees).
Each Employee object has an id, a company_id (foreign key), a badge_number, a last_updated datetime field, name, etc
Easy, right?
Now comes the tricky part...
Each day I get (from an API) a $company_upd array that contains the list of all the companies that updated some of their employees data. Then, for each company in $company_upd, I retrieve from the API a $company_employees_list array that cointains the new list of employees .
Then I loop through the array to identify any new/updated record that needs to be persisted in my local database. Like this:
foreach ($company_employees_list as $employee){
$local_employee = $repo->findOneBy("badge_number" => $employee["badge_number"];
//if there is already an employee record with the same badge_number
if($local_employee){
//compare the last_updated field to see if this employee record needs to be updated
if($employee["badge_number"] > $local_employee->getLastUpdated()){
//update the record and persist to the database
$local_employee->setSomething($employee["some_value"];
}
} else {
//create a new employee object and persist it to the database
$new_employee = new Employee();
$new_employee->setSomething('some_value');
$em->persist($new_employee);
}
}
$em->flush();
Of course, this approach works fine BUT I'm doing a query foreach employee foreach company!! (to retrieve the corresponding object and update it)
Is it possible (and would it be better) to use the ArrayCollection? I mean: fetch the employees ArrayCollection ONE TIME and then, work with it. Search if there is already an employee record with a specific badge_number and eventually update it and persist it to the database?
So, basically, I would like to do everything I did in the code above but using Array_Collection instead of separate queries.
But only if this new approach is faster/better.
If it is indeed possible (and faster), could you please write some mockup code to better understand HOW to manipulate an ArrayCollection and do what I want?
//Fetch the local db employees ArrayCollection
$employees_ar_coll = $company->getEmployees();
//What now???? =)
P.s. The API works like this, can't change that.

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.

RestFul webService and Database Transactions

Lately i'm struggling with Rest architecture :p and i usualy raise a lot of problems with it.
Let's say that i have a resource named "user", and that user can have a list of cars.
Im trying to insert that user and his list of cars in the database at once. I know i have to do this with the POST HTTP verb. But how would i achieve this? Should i send only one URL with the user identification and the list of cars somehow encoded or should i use the "user" resource to insert the user, and then for each car, call a POST URL in a resource named "car"?
The second approach has a problem. This process must be implemented with a Database Transaction. If something goes wrong when inserting a car, i want the user to not be regitered in the database.
I know restFul architectures must be stateless, so how can i implement such a transaction using the database functionalities? I know i can implement myself some kind of transaction, but i wanted it to be more automaticaly.
Thanks in advance.
There are a number of ways you can do it depending on the languages you're using in the front and backend and how you plan to send this data. I would solve the problem like so, assuming you're using PHP and MySQL:
Get the data ready, so something like user=123&cars[]=1&cars[]=2&cars[]=3 (I'm using the var cars[] as this will send an array to PHP and you can achieve this by naming your input fields as cars[])
Post this to your backend
Your backend will then process the user and add them to the database if they're not there.
I would then have a table that illustrated the relationship between the user and the cars, something along the lines of:
CREATE TABLE box_to_category (
user_id int(11) NOT NULL,
car_id int(11) NOT NULL
);
In this table I'd clear all cars associated with that user and then add the new cars as POSTed to the backend (the user_id will be associated to a user in a users table and the car_id will be associated to a car in the cars table)
It's a simple set up.

Categories