Storing/updating multiple rows in from same method in Laravel - php

I have a table like this
month | rate | admin_id
0 | 1000 | 1
I am storing data with following method:
public function store(Request $request)
{
foreach ($request->admin_id as $key => $val){
$adminbillings = AdminBilling::create([
'month' => 0,
'rate' => $request->rate[$key],
'admin_id' => $val,
]);
}
return redirect('/');
}
When I add a new row in the table using this method, I also want to replace the month of previous row (which is 0) with the timestamp of the new line. So the table will become
month | rate | admin_id
29-08-2017 | 1000 | 1
0 | 2000 | 1
I can add multiple lines from single method, but here one is store and one is update, and by default update requires two arguments. But may be I am mistaken somewhere. Can you please guide me how to achieve my target?
I can access the previous row inside the method using this line:
$ended_at = AdminBilling::where('admin_id', $val)->where('month', 0)->get();

This is not best solution but you will achieve your target.
To update previous record after insertion , you can do like this -
$res = AdminBilling::select('id')->orderBy('id','desc')->skip(1)->take(1)->first(); //to get prev. row
AdminBilling::where('id',$res->id)->update(['month',date()]); // to update month
put these lines in your store function as -
public function store(Request $request)
{
foreach ($request->admin_id as $key => $val){
$adminbillings = AdminBilling::create([
'month' => 0,
'rate' => $request->rate[$key],
'admin_id' => $val,
]);
$res = AdminBilling::select('id')->orderBy('id','desc')->skip(1)->take(1)->first();
AdminBilling::where('id',$res->id)->update(['month',date()]);
}
return redirect('/');
}
Hope this will helpful for you.

When you use create method it returns the instance of your inserted row. So you can use $adminbillings->id if you need the access to previously insterted row.

Related

How to update multiple rows in sql from array data using laravel eloquent

I was trying to update multiple records in my database using laravel eloquent but is getting errors when trying to update using an array.
I am not really sure how to correctly get the data from the array to my update function.
The array I am passing looks like this.
My Database table looks like
id | checklistid | categoryid | isCheck | created_at | updated_at
My Controller looks like this.
public function updateCategoryListData(Request $request){
$checklistdata = $request->get('checklist');
$id = $request->get('checklistid');
$dataset = [] ;
foreach($checklistdata as $key =>$value){
$dataset[] = ['checklistid'=>$id,'categoryid' => $key,'isCheck'=>$value];
}
categorylistcontent::where([['checklistid',$id], ['categoryid', $dataset=>['categoryid'] ]])
->update($dataset['isCheck']);
}
Would you be able to advise how I can use the array to get the 'checklistid' and 'categoryid' to be used as the where clause of the update statement and then the 'isCheck' to be set in the update.
You don't need dataset array, rather do the following:
foreach($checklistdata as $key =>$value){
categorylistcontent::where('checklistid',$id)->where('categoryid',$key)
->update(['isCheck'=>$value]);
}
You can't do that with just one query, but you could do that with two queries. An example:
$check = categorylistcontent::query();
$notCheck = categorylistcontent::query();
foreach ($request->checklist as $item) {
$query = $item['isCheck'] === 1 ? 'check' : 'notCheck';
$$query->orWhere(function($q) use($item) {
$q->where('checklistid', $item['checklistid'])->where('categoryid', $item['categoryid']);
}
}
$check->update(['check' => 1]);
$notCheck->update(['check' => 1]);
I haven't tested this exact code, but I think it will be helpful for you to get the idea.
You need to update multiple rows by putting it in foreach loop
eg:
foreach($checklistdata as $key =>$value){
$dataset[] = ['checklistid'=>$id,'categoryid' => $key,'isCheck'=>$value];
categorylistcontent::where([['checklistid',$id], ['categoryid', $dataset=>['categoryid'] ]])
->update($dataset['isCheck']);
}

Preventing multiple value in 3 column in laravel 5.5

I have get problem on this case, I don't know how to prevent multiple value in 3 column, I mean if the 3 column have multiple value it will not insert to database,for example I have Krs table where has data like this :
| id | nim | nip | kode_mk
| 1 | 134 | 154 | 543
and laravel will ignore this data when someone insert data like this :
nim=134,nip=154,kode_mk=543 laravel will not insert and give an
atttention
but laravel will accept if data like this :
nim=1132,nip=154,kode_mk=543 laravel will accept and save to database
nim=134,nip=1984,kode_mk=543 laravel will accept and save to database
nim=1345,nip=154,kode_mk=543 laravel will accept and save to database
I have a table like this where I want prevent the data in the black circle:
this my Krs.php :
protected $fillable = ['nim','nip','kode_mk','absen','uts','uas'];
protected $table = 'krs';
public function mahasiswas(){
return $this->belongsToMany('App\Mahasiswa','id');
}
public function dosens(){
return $this->belongsToMany('App\Dosen','id');
}
public function makuls(){
return $this->belongsToMany('App\Matakuliah','id');
}
this my KrsController.php :
public function store(KrsRequest $request)
{
$krs = new Krs([
'nim' => $request->get('nim'),
'nip' => $request->get('nip'),
'kode_mk' => $request->get('kode_mk'),
'absen' => $request->get('absen'),
'uts' => $request->get('uts'),
'uas' => $request->get('uas')
]);
if ($krs->save()) {
session()->flash('status','done_all');
session()->flash('pesan','Data berhasil disimpan');
}else{
session()->flash('status','clear');
session()->flash('pesan','Data gagal disimpan');
}
return redirect('Akademik/Krs/create');
}
I don't know how to explain it in english , sorry for my bad grammar
EDIT 1 Table Structure
In your Krs migration, set the field to require the value to be unique. For example:
$table->string('kode_mk')->unique();

Laravel 5 - update overwriting all data

I have a Document Model which represents a Document (name, description etc). I then have a DocumentData Model which represents the data of a Document. A Document has One to Many DocumentData,
So to create a Document I have a form. Lets say that my form has a text input for Document Owner. Within my DocumentData table, the label documentOwner is set as the key and the inputted data is set as the value. So with multiple form elements, my DocumentData table might look like this
document_data
id | documentId | key | value |
----------------------------------------------
1 | 1 | clientName | Google |
----------------------------------------------
2 | 1 | projectName | Analytics |
----------------------------------------------
3 | 1 | Contact | Mr Sharp |
----------------------------------------------
4 | 1 | startDate | 29/12/2016 |
----------------------------------------------
The Document name and description for the Document table is created using hidden fields within the view of the Document.
So I can create Documents without a problem. I am having a problem with my update function though. So far I have the following
public function update(Request $request, Project $project, $id)
{
$document = $project->document()->where('id', '=', $id)->first();
$docData = $document->documentData()->get();
$input = $request->all();
foreach($docData as $orgData) {
foreach($input as $key => $value) {
if($key !== "filePath" && $key !== "documentType" && $key !== "documentTypeDesc") {
if($key == $orgData->key) {
$orgData->value = $value;
$orgData->update();
}
}
}
}
return View::make($document->name.'Doc.edit', compact('project', 'document'));
}
So firstly I get the Document I am working on and store it in $document. I then get the DocumentData for this Document and store it in $docData. $docData is a collection containing my key-value pairings for a Document.
I then loop both the $docData and the inputted data and where the keys match, I reset its updated value.
However, at the moment, it updates everything to the last inputted data field. I am not sure where else I can perform the update operation, but I only need it to update the row it is referring too, not the whole thing.
How could I go about doing this?
Thanks
I've cleaned up the code a little, and made a few implementation changes. This code should work, so let us know if it doesn't, and if not, what failed.
public function update(Request $request, Project $project, $id)
{
// you can use eager loading and find on the relationship query
$document = $project->document()->with('documentData')->find($id);
// you can just access the relationship attribute, no need for the query
$docData = $document->documentData;
// gets all input, except the keys specified
$input = $request->except(['filePath', 'documentType', 'documentTypeDesc']);
foreach($docData as $orgData) {
// check if the input has a key that matches the docdata key
if (array_key_exists($orgData->key, $input)) {
// update the value
$orgData->value = $input[$orgData->key];
// use save, not update
$orgData->save();
}
}
return View::make($document->name.'Doc.edit', compact('project', 'document'));
}

Mass assignment issue

I have a form with a lot of fields and each of them has to be added in a table as a different row.
My table looks like this:
| Category | Device | Value |
|----------|:-------|-------------|
| 2 | 1 | some value |
| 3 | 1 | other value |
| 7 | 3 | etc |
The Category and Device are actually foreign keys from the Categories and Devices tables. Also they should be unique, meaning that there can't be Category: 2 and Device: 1 twice. If they exists already, the value should be updated.
The categories and value are retrieved from the form and it looks like this:
{"2":"some value","3":"other value","5":"etc","6":"something","8":"can be empty"}
The device also comes from the form but it will be the same.
Now I need to enter everything in my database and I'm looking for a simple solution.
But it will do about 100 queries (one for each input) and I'm sure there must be a better solution.
If one of the values that comes from the form is empty, it should be ignored.
Here's my currently working code, maybe you can understand better:
public function postSpecs(Request $request)
{
$specs = $request->except(['_token', 'deviceid']);
foreach($specs as $key=>$val)
{
if($val == '') continue;
if(Spec::where('category', $key)->where('device', $request->deviceid)->exists())
{
$spec = Spec::where('category', $key)->where('device', $request->deviceid)->first();
$spec->value = $val;
$spec->save();
}
else
{
$spec = new Spec;
$spec->category = $key;
$spec->device = $request->deviceid;
$spec->value = $val;
$spec->save();
}
}
}
use the insert method like:
$model->insert([
['email' => 'taylor#example.com', 'votes' => 0],
['email' => 'dayle#example.com', 'votes' => 0]
]);
See also: http://laravel.com/docs/5.1/queries#inserts
EDIT:
Updated to your code:
public function postSpecs(Request $request)
{
$specs = $request->except(['_token', 'deviceid']);
$data = array();
foreach($specs as $key=>$val)
{
if($val == '') continue;
if(Spec::where('category', $key)->where('device', $request->deviceid)->exists())
{
$spec = Spec::where('category', $key)->where('device', $request->deviceid)->first();
$spec->value = $val;
$spec->save();
}
else
{
$data[]['category'] = $key;
$data[]['device'] = $request->deviceid;
$data[]['value'] = $val;
}
}
Spec::insert($data);
}
While this is not perfect, it will save you a lot queries. Else you have to use raw query something like (untested!):
INSERT INTO spec (id,category,device,value) VALUES (1,2,3),(4,5,6)
ON DUPLICATE KEY UPDATE id=LAST_INSERTED_ID(id)
A little more information on the on duplicate key update method because I think it deserves to be a possible solution if this is something that's going to happen a lot...
First, you would need to create the unique key. This will force those columns to be unique. I'd highly suggest adding the unique key no matter how you handle the inserts. It may help preserve your sanity in the future.
In a migration, you would do...
$table->unique(['Category', 'Device']);
Or in plain sql...
alter table category_device add unique index unique_category_device (Category, Device);
Now to insert into the table, you would simply use the query...
insert into category_device (Category, Device, Value) values ($category_id, $device_id, $value)
on duplicate key udpate Value = VALUES(Value)
If it's not a duplicate entry, mysql will simply insert the new record. If it is a duplicate, mysql will update the value column with whatever you tried to insert as the new value. This is very performance friendly as you will not be required to check for the existence of duplicates before trying to do the insert as it will simpy act like an update statement in the event there is a duplicate. The drawback here is laravel does not support on duplicate key update so you would need to actually write the SQL. I would suggest you still use data bindings though which can make it somewhat easier.
$sql = "insert into category_device (`Category`, `Device`, `Value`) values (:category_id, :device_id, :value)
on duplicate key udpate Value = VALUES(Value)";
$success = \DB::insert($sql, [
'category_id' => $category_id,
'device_id' => $device_id,
'value' => $value
]);
Also please note, if you have over 100 entries, you could loop through them and keep adding to the query and it should work just the same...
insert into category_device (`Category`, `Device`, `Value`)
values
(1, 1, 'some value'), (1, 2, 'some other value'), (1, 3, 'third value')...
on duplicate key udpate Value = VALUES(Value)";
If you are using this method, I would probably not worry about the data binding and just insert the values right into the query. Just make sure they are properly escaped beforehand.
If you had a hundred items to insert, which would be 200 queries (one for checking the existence of the record, and another for inserting/updating), this would turn that 200 queries into 1 query which obviously would be a huge performance gain.

Issue in updating contract record in Codeigniter

I am trying to update each contract I have for a particular job entry. My condition is for every job I post, more than one applicant can be hired. Right now, this is what my code shows.
Job ID | Job Title | Provider | Contract Status | Provider's Feedback | Note to Self
1 | First job.| Provider1| DONE | |I like his work.
1 | First job.| Provider2| DONE | |I like his work.
This is supposedly correct but just until PROVIDER column. Whenever I click job title entry (I have it linked to another page where I can update the contract), I should be able to write something about the worker - if the job was done, how his performance was (which should be view-able on his equivalent page), and my note to self about him. Problem is, whenever I click one of the contracts and make an update, all the contracts will be affected. How will I make it unique?
Here's my code so far:
public function update_job_contract($post_obj)
{
$id = $post_obj['id'];
$data = array
(
'client_feedback' => $post_obj['client_feedback'],
'client_notetoself' => $post_obj['client_notetoself'],
'contract_status' => $post_obj['contract_status'],
'client_id' => $this->auth_model->get_user_id()
);
$this->db->where('id', $id);
$this->db->update('job', $data);
}
in my controller:
public function update_job_contract()
{
$this->validateRole('client');
$this->load->model('job_model');
$id = $this->uri->segment(3,0);
$data['job'] = $this->job_model->get_job($id);
$this->load->view('client/update_job_contract', $data);
}
public function update_job_contract_submit()
{
$this->validateRole('client');
$this->load->model('job_model');
//if ( '0' == $_POST['id'] ) {
$this->job_model->update_job_contract($_POST);
//}
redirect('client/manage_job_contracts?message=Congratulations!');
}
I am looking forward to getting help! Thanks!

Categories