Laravel 5 eloquent model won't let me update - php

I do have the invitations table set up and in the database. I use it for other purpose such as adding more...
my goal: update the first record with a new value to a field:
I tried:
$invitation = new MemberInvitation();
$invitation1 = $invitation->find(1);
$invitation1->status = 'clicked';
$invitation1->save();
And also:
$invitation1 = \App\Model\MemberInvitation::find(1);
$invitation1->status = 'clicked';
$invitation1->save();
both ended with:
Creating default object from empty value
EDIT:
This piece of code worked and updated my records correctly -- I just can't do it via Eloquent's model:
\DB::table('member_invitations')->where('id', '=', $member_invitation->id)
->update(array('status' => 'clicked', 'member_id' => $member->id));
what am I missing?

Try this.
$invitation = MemberInvitation::findOrFail(1);
$invitation->status = 'clicked';
$invitation->save();
If that doesnt work, please show your model

find(1) doesn't mean "give me the first record", it means "give me the first record where id = 1". If you don't have a record with an id of 1, find(1) is going to return null. When you try and set an attribute on null, you get a PHP warning message "Creating default object from empty value".
If you really just want to get the first record, you would use the first() method:
$invitation = \App\Model\MemberInvitation::first();
If you need to get a record with a specific id, you can use the find() method. For example, to translate your working DB code into Eloquent, it would look like:
$invitation = \App\Model\MemberInvitation::find($member_invitation->id);
$invitation->status = 'clicked';
$invitation->member_id = $member->id;
$invitation->save();

The answer is obvious based on your reply from May 15th.
Your "fillable" attribute in the model is empty. Make sure you put "status" in that array. Attributes that are not in this array cannot up modified.

Related

Laravel/Mysql: unable to set field to null

I am working on a laravel project and trying to duplicate a record in mysql db.
after replication I want to set a field value to null(appointment_status).
everything is working except the new record's value (appointment_status) is the same as the original record even tho I set it to null.
$newAppointment = $appointment->replicate();
//push to get the id for the cloned record
$newAppointment->push();
$newAppointment->duplicated_from_id = $appointment->id;
$newAppointment->appointment_status = null;
$newAppointment->save();
//updating the old appointment
$appointment->duplicated_to_id = $newAppointment->id;
$appointment->save();
Instead of whole code-block, try something like this:
// replicate as the new record with some different fields
$newAppointment = $appointment->replicate()->fill([
'duplicated_from_id' => $appointment->id,
'appointment_status' => null,
])->save();
// update some fields of initial original record
$appointment->update([
'duplicated_to_id' => $newAppointment->id,
]);
For more check out this.

Laravel Eloquent: any way to update DB with dynamic fields?

I am trying to implement the "Edit Application Settings" feature. After a bit of thinking, my configuration values are stored in the DB with key -> value structure, like this:
id
key
value
1
logo_path
img/logo.png
As you can see, for each setting, there is only a key & value column. I made an App Service provider to cache them forever, and a helper function (config('setting_key')) to get the value, but now I'd like to update it in the most efficient way.
The user interface consists of the <form action="post" ...> and input with a corresponding name, like this: <input name="setting_key_name" ... />. As you can see, the name attribute here has the value of the key column value and the actual value of the input would be the value column value (a bit of confusion here).
First thing that came to my mind, was to make a foreach loop and find & update every row in DB, but IMHO it is very unoptimized way, cause if the page has a form with 10 values, it is 10 SQL queries. But till now, this is what I've done:
$keys = collect($request->except('_token'))->keys()->toArray();
// get all settings if the key name matches the request's input name
$setting = Setting::whereIn('key', $keys)->get();
$logo = self::GENERAL_APP_LOGO; // contant with a key-name (general_application_logo);
if($request->has(self::GENERAL_APP_LOGO) && $request->$logo) {
// Processing uploaded image here;
$this->uploadLogo($image, self::LOGO_IMAGE_PATH, $name); // Using an upload trait
$setting->where('key', $logo)->value = self::LOGO_IMAGE_PATH . $name; // just a try to update the DB this way
}
foreach ($keys as $key) {
$setting->where('key', $key)->value = $request->$key; // putting all request's input values to corresponding key
}
$setting->save(); // saving the DB.
As you can see, this won't work and will throw an Exception, like Call to undefined method ...\Eloquent\Builder::save(). I tried the same code with an update, but the difficult part here is to update it multiple times (since the if section should have the update as well, for the logo), as well as binding the key to value.
So, a little bit of your help would be appreciated - what the logic should be here? How can I update a DB rows with corresponding column's value? I mean - like this (update where key = 'general_app_name' set value, 'some_setting_value'), but using the optimized and clear way?
Working solution
As #miken32 stated in his answer, I used hid version of code, but with slight changes:
// Changed the $request->settings->keys() to PHP native method array_keys():
$settings = Settings::whereIn('key', array_keys($request->settings))->get()->groupBy('id');
// Also, here I changed the `whereIn('id', ...)` to `whereIn('key', ...)`, since it was my primary index.
foreach ($request->settings as $k=>$v) {
if ($k === self::GENERAL_APP_LOGO_ID) {
// not sure about this one, but I think this is
// how you'd access a file input in an array
$image = $request->file('settings')[$k];
$this->uploadLogo($image, self::LOGO_IMAGE_PATH, $name);
$v = self::LOGO_IMAGE_PATH . $name;
}
// take the Setting object out of the list we pulled
// Here I added the ->first() to get the first element from the retrieved collection;
$setting = $settings->get($k)->first();
$setting->value = $v;
$setting->save();
}
Since I was fetching the configuration values via helper, that only returns the value of the current key (and no id column), I changed the id to key and made the key as my PK in a model. Works like a charm!
With each setting in a separate row, there's no way to avoid multiple database queries – one to get the current values for all settings, and other to update each one. Looking up items by primary key is more efficient, so I'd recommend putting the contents of the id column in your blade view, like this:
<label for="setting_{{$setting->id}}">{{$setting->key}}</label>
<input name="settings[{{$setting->id}}]" id="setting_{{$setting->id}}" value="{{$setting->value}}"/>
Now in your controller, $request->settings will be an array you can loop through. You can continue treating your file upload separately, but now you've got the id column to look up, so change your constant to that.
$settings = Settings::whereIn('id', $request->settings->keys())->get()->groupBy('id');
foreach ($request->settings as $k=>$v) {
if ($k === self::GENERAL_APP_LOGO_ID) {
// not sure about this one, but I think this is
// how you'd access a file input in an array
$image = $request->file('settings')[$k];
$this->uploadLogo($image, self::LOGO_IMAGE_PATH, $name);
$v = self::LOGO_IMAGE_PATH . $name;
}
// take the Setting object out of the list we pulled
$setting = $settings->get($k);
$setting->value = $v;
$setting->save();
}
Note that Laravel does offer methods to bulk-update multiple models at once, but they are doing separate queries to the database in the background. IIRC, the save() method doesn't do anything if the value hasn't changed, which will spare you some hits.
You could try creating a text field, or a json field if your database supports it, and storing all of your settings as a JSON string in that field.
id
settings
1
{ "logo_path" : "img/logo.png", "foo" : "bar", "thing_count" : 17 }
2
{ "logo_path" : "img/logo2.png", "foo" : "baz", "thing_count" : 4 }
In your Laravel model, you can cast it as an array
protected $casts = ["settings" => "array"];
and then use it from the model
echo $theModel->settings['logo'];
echo $theModel->settings['foo'];
or you can cast it as a fully fledged object if you need to using value object casting.
One gotcha that can be confusing for people is the setting of the values in the array to update it. This will not work:
$theModel->settings['foo'] = "boz";
The reason is due to the way the Laravel mutators work. Instead, you make a value copy of the settings, change that, and reassign it to the model:
$settings = $theModel->settings;
$settings['foo'] = "boz";
$theModel->settings = $settings;
This approach has the capacity to infinitely expandable in the future as you just add new keys to your json. Be sure to do checks on the settings array to ensure fields you are looking for are set (which is why value objects can be very handy to do validation).
It also solves your database query problem - it's only ever one.
You don't need to put
$setting->where('key', $logo)->value = ...;
Just call
$setting->where('key', $logo)->update($request->toArray());
$setting->save(); called when you instantiated setting class like :
$setting = new Setting();
Or
$setting = Setting::whereIn('key', $keys)->get()->first();
Then
$setting->val = ...;
$setting->save(); // then it work's

How to select the last row from database in laravel [duplicate]

This question already has answers here:
Select Last Row in the Table
(22 answers)
Closed 4 years ago.
public function addNewPost(Request $request)/****ADD new POST****/
{
$this->validate($request,['post_title'=>'required|min:4|max:100',
'post_description'=>'required|min:20|max:500'
]);
$user_name = Session::get('name');
$post_title = $request->input('post_title');
$post_description = $request->input('post_description');
$addPost = new AddNewPost(['user_name'=> $user_name, 'post_title'=> $post_title, 'post_description'=> $post_description]);
$addPost->save();
$addPost->post_id;
//$addPost = DB::table('userposts')->where(['user_name'=>$user_name ])->orderBy('post_id', 'desc')->get();
print_r($addAdmin->post_id); //This is printing nothing, i.e. blank.
}
post_id column in userposts table is auto incremented. I am trying to get the last post id of the user by user_name. I have seen some tutorials and also checked some questions over internet but unable to do what I am trying to get. Can anybody know how to do it. Thank you.
Try first() instead of get() in a query it might help you
$lastdata = DB::table('userposts')->where(['user_name'=>$user_name ])->orderBy('post_id', 'desc')->first();
print_r($lastdata);
Laravel has the last() method that you can use.
This is from the docs:
last()
The last method returns the last element in the collection that passes a given truth test:
collect([1, 2, 3, 4])->last(function ($value, $key) {
return $value < 3;
});
// returns 2
You may also call the last method with no arguments to get the last element in the collection. If the collection is empty, null is returned:
collect([1, 2, 3, 4])->last();
//returns 4
Here is the example for getting only the last id:
Model::pluck('id')->last();
DB::table('userposts')->last()->pluck('user_name') Is the fastest way .
Make sure to apply last() first to avoid unnecessary workload
Simple method which will not takes much processing is
DB::getPdo()->lastInsertId();
Hope this helps
You can also try
$addPost = new AddNewPost(['user_name'=> $user_name, 'post_title'=> $post_title, 'post_description'=> $post_description]);
$addPost->save();
$addPost->update();
print_r($addPost->post_id); //It will print id..
P.S second method is kind of redundant
Hope this helps
Please have a closer look at your print statement:
print_r($addAdmin->post_id);
The $addAdmin is not defined within the scope of your function. The best way to get the last row from your database:
DB::table('name_of_table')->last()->pluck('user_name')
Here is the documentation on using DB: https://laravel.com/docs/5.6/database

Update a row using idiorm and php

I have this function to update a record, but i cannot it fails and send me a "Primary key ID missing from row or is null" message, how can I fix it?
public static function update_child($data)
{
try
{
$update= ORM::for_table("dm_child",DM_TAG)
->where_equal($data["id_child"]);
$update -> set(array(
"gender" => $data["gender"]
"age_year" =>$data["year"]
"age_month" => $data["month"]
));
$update -> save();
}
catch(PDOException $ex)
{
ORM::get_db()->rollBack();
throw $ex;
}
}
Idiorm assumes that the name of the primary key is 'id', which is not that, in your case.
Therefore you have to explicitly specify it to Idiorm:
<?php
ORM::configure('id_column_overrides', array(
'dm_child' => 'id_child',
'other_table' => 'id_table',
));
See Docs>Configuration.
The answer is indeed the one provided by #iNpwd for changing the default 'id' column name for queries on a per table basis:
ORM::configure('id_column_overrides', array(
'table_name' => 'column_name_used_as_id',
'other_table' => array('pk_1', 'pk_2') // a compound primary key
));
The thing that was biting me on getting it to recognize my query was WHERE I was changing the ORM::configure values. I was not in the correct file.
A deeper link to specifically the ID Column configuration: http://idiorm.readthedocs.org/en/latest/configuration.html#id-column
I just met this problem 2 minutes ago. The real reason is, you forgot select id field in querying.
demo:
$demo = ORM::for_table('demo')->select('field_test')->find_one($id);
$demo->field_test = 'do';
$demo->save();
You will get the error.
change to :
$demo = ORM::for_table('demo')->select('field_test')->select('id')->find_one($id);
It will fix the problem.
Some tips in documents:
https://github.com/j4mie/idiorm/blob/master/test/ORMTest.php
/**
* These next two tests are needed because if you have select()ed some fields,
* but not the primary key, then the primary key is not available for the
* update/delete query - see issue #203.
* We need to change the primary key here to something other than id
* becuase MockPDOStatement->fetch() always returns an id.
*/
I've never used idiorm, so cannot guarantee that my answer will work for you, but from this page and under "Updating records", we have an example which is similar but slightly different to yours.
// The 5 means the value of 5 in the primary-key column
$person = ORM::for_table('person')->find_one(5);
// The following two forms are equivalent
$person->set('name', 'Bob Smith');
$person->age = 20;
// This is equivalent to the above two assignments
$person->set(array(
'name' => 'Bob Smith',
'age' => 20
));
// Syncronise the object with the database
$person->save();
I'm sure I'll learn the reason behind this, but let me tell you all I understand at the moment, and how I "fixed" it.
Here is the beginning of idiorm's save function:
public function save() {
$query = array();
// remove any expression fields as they are already baked into the query
$values = array_values(array_diff_key($this->_dirty_fields, $this->_expr_fields));
if (!$this->_is_new) { // UPDATE
// If there are no dirty values, do nothing
if (empty($values) && empty($this->_expr_fields)) {
return true;
}
$query = $this->_build_update();
$id = $this->id(true);
Right there, on that last line, when trying to access the $this->id, you are getting an exception thrown:
throw new Exception('Primary key ID missing from row or is null');
$this does not contain an id property. I'm not really sure how it could. The example given both on their homepage and in the docs doesn't do anything special to address this. In fact I am copying them 1:1 and still yielding the same error as you.
So, all that said, I fixed this error by just adding in my own id:
$crop = ORM::for_table('SCS_Crop')->find_one($id);
$crop->id = $id;
$crop->Name = "Foo";
$crop->save();
This also happens when the id field name is ambiguous, e.g. when joining two tables both having an id column. This is the case with referenced tables
Model::factory('tableOne')
->left_outer_join('tableTwo', array('tableOne.tableTwo_id', '=', 'tableTwo.id'))
->find_one($id);
In these cases set an alias to the ID column of the parent tableOne to later access it while saving. Make sure that you also select other columns you need - e.g. by ->select('*'):
Model::factory('tableOne')
->select('*')
->select('tableOne.id', 'id')
->left_outer_join('tableTwo', array('tableOne.tableTwo_id', '=', 'tableTwo.id'))
->find_one($id);
if in table primary key/ field name not id then following id column overrides required
default id (primary_key) to replace with other id name (primary_key)
ORM::configure('id_column_overrides', array(
'user' => 'user_id',
));
$update = ORM::for_table('user')->find_one(1);
$update->name = "dev";
try{
$update->save();
}catch(Exception $e){
echo $e;
}
print_r($update);

update query for Mongodb in yii

How can I update based on _id in mongodb for YII?
What I tried is
$model= new MongoUrls();
$criteria = new EMongoCriteria;
$criteria->userid('==', $userid);
$criteria->screenshot_path('!=', null);
$criteria->screenshot_uploaded('!=', 1);
$availablescreenshots=$model-> findAll($criteria);
if(count($availablescreenshots)>0){
foreach($availablescreenshots as $obj1){
$path_parts = pathinfo($obj1->screenshot_path);
if($social->upload($obj1->screenshot_path, 'test',$path_parts['basename'])) {
$model->updateAll(array('_id'=>$obj1->_id ), array('screenshot_uploaded'=>1) );
}
}
}
But it shows an error "The EMongoDocument cannot be updated because it is new." in Yii .
I want to update a document where _id matches same value
If I am correct in assuming the extension you are using you actually want $model->updateAll() since update() relates to updating the current active record not to running a general query. It is a bit confusing but it is the way Yii works.
As yii mongosuite docs states, updateAll is a bit different in use than usual update. Also, you are using updateAll in loop and as condition you pass single id which not really makes sense. With updateAll you could use criteria to update models. Here you should use partial update like that:
// _id is already set because it comes from db
$obj1->screenshot_uploaded = 1;
// First param to set fields which should be updated
// Set second param to true, to make partial update
$obj1->update(array('screenshot_uploaded'), true);
The method worked for me was
$modifier = new EMongoModifier();
$modifier->addModifier('screenshot_uploaded', 'set', '1');
$criteria = new EMongoCriteria();
$criteria->addCond('_id','==', $obj1->_id );
$model->updateAll($modifier,$criteria );

Categories