Laravel 5.4 save NULL to database not working - mysql

The following code results in an empty value inside the database and when I get it out of the database its an empty String.
$customer->update(['company' => NULL]);

You should consider 3 things:
1) Make sure company column in nullable in your table. If it's not it won't be possible to put null in there.
2) Make sure you have in $fillable property of Customer model column company
3) Verify you don't have any mutator in your Customer model - so verify you don't have setCompanyAttribute method that might change value automatically to empty string if it's set to null

SOLUTION
If you want a field inside the database to be null and you do not use a mutator everything is fine.
Are you using a mutator, in my case the following snippet.
public function setCompanyAttribute($value)
{
$this->attributes['company'] = ucfirst($value);
}
Then you need to check if $value is null and then set it manually to null otherwise it will be an empty string.
To do that automatically on every model you can set the empty string back to null inside your EventServiceProvider.
Event::listen('eloquent.saving: *', function ($eventName, array $data) {
$attributes = [];
foreach ($data as $model) {
foreach( $model->getAttributes() as $key => $value ) {
$attributes[$key] = (is_string($value) && $value === '') ? null : $value;
}
$model->setRawAttributes($attributes);
}
return true;
});
It's important to first check all attributes from the model and set it to a temporary array. Now inside the setAttribute() method on the model instance the checks are done if a mutator exists. But thats exactly what you do not want, because it would set all fields with a definied mutator to an empty sting. Instead use setRawAttribute so the old attributes are overwritten with the ones from the temporary array.
This is safe to do because if the checked value isn't an empty string the already existing value is taken for that field. Otherwise if it's an empty string then null is set.
Hope it helps!

Related

Laravel 5.8 BIT(1) datatype issue

I have a column enabled with datatype bit(1). I am trying to save 0 or 1 value in Database by Laravel eloquent.
$model->enabled = $inputs['enabled'];
$model->save();
I have saved values in my config file.
'enabled' => [
'0' => 'No',
'1' => 'Yes',
],
But when I tried to save these value in database. I was getting error like,
SQLSTATE[22001]: String data, right truncated: 1406 Data too long for column 'enabled' at row 1
when i ran query in mysql phpmyadmin, it saved data correctly database.
But running this query by eloquent, it produces error.
you need tinyint type, in your migration file do
$table->boolean('enabled')->default(false);
When you migrate with boolean('column_name') it creates a column with type tinyint(1) and you can set to model true/1 or false/0 and save. For example
$model->boolean_field = true;
$model->save();
Or
$model->boolean_field = 1;
$model->save();
As per MySQL manual you can use should use bool and boolean which are aliases of tinyint to store 0 or 1 value
TINYINT: A value of
zero is considered false. Non-zero
values are considered true.
So use:
$table->tinyInteger('enabled');
https://dev.mysql.com/doc/refman/8.0/en/other-vendor-data-types.html
A boolean in mysql is generaly a tinyint.
Eloquent models can cast boolean automaticaly : https://laravel.com/docs/6.x/eloquent-mutators#attribute-casting
protected $casts = [
'enabled' => 'boolean',
];
Before saving your model, make sure your variable is a boolean
$model->enabled = $inputs['enabled']==='Yes';
$model->save();
also you can use mutator to force values.
example : in your model, append :
public function setEnabled($value) // note the E in uppercase.
{
if ($value=='YES') { $this->attributes['enabled'] = 1;
if ($value=='NO') { $this->attributes['enabled'] = 0;
if ($value=='1') { $this->attributes['enabled'] = 1;
if ($value=='0') { $this->attributes['enabled'] = 0;
// etc...
// the logic can be improved... yes/YES/No/no/0/1/empty/null/ etc..
}
and in the client code
$model->enabled = 'YES'; // || 'NO' || etc.., : note the e in lowercase.
then method setEnabled is called during assignation and 'enabled' will become 1
doc : https://laravel.com/docs/5.8/eloquent-mutators
So i had solved my question by just adding DB::raw();
like,
$model->enabled = DB::raw($inputs['enabled']);
$model->save();
Eloquent doesn't work by calling Boolean value directly, first you have to gone through your values in DB::raw();
It works like a charm.

Yii2 - Checkboxlist Value Store In Database

in my db structure
service_request type enum('towel','tissue','napkin')
then have a model
* #property string $service_request
then in my view
<?= $form->field($model, 'service_request')->checkBoxList([ 'towel' => 'Towel', 'tissue' => 'Tissue', 'napkin' => 'Napkin']) ?>
then when i choose towel, tissue and napkin then submit the form, it's have an error said
Service Request must be String
please help me
Thank You
Like Joji Thomas said, checkBoxList prodices an array.
You need to change your database structure so that it supports 1-to-many relations (each $model can have multiple service_requests) if you want to save this. Unfortunately Yii is not very good at this sort of thing out of the box so you have to do a bunch of things yourself.
First you need to create a ServiceRequest ActiveRecord.
Then your $model needs to have a relation like:
public function getServiceRequests() {
return $this->hasMany(ServiceRequest::className(), ['model_id' => 'id'];
}
Then in your controller (model create action) you will need to do something like this:
foreach (Yii::$app->request->post('ServiceRequest',[]) as $data) {
$item = new ServiceRequest($data);
$model->link('serviceRequests', $item);
}
If you wanna update the checkboxes too then you need to do something similar in your model update action as well.
Please change checkBoxList to radioList, because when selecting multiple values service_request becomes an array. Enum type can handle only string values.
First change your filed datatype from enum to varchar. enum only takes a single string value.
Secondly you need to implode service_request array to string for save to db.
Use bellow code before the model save function :
$model->service_request = implode("," , $model->service_request);
$model->save();

Save Model Values Without Null

Everytime i try attempt to update a row i receive an error which says "something is required". In codeigniter you can update rows without the need to set everything to null in the mysql tabel settings.
I just want to update one value not the entire row.
Is this possible?
if ($users->save() == false) {
echo "Umh, We can't update the user right now: \n";
foreach ($users->getMessages() as $message) {
echo $message, "<br>";
}
$this->flash->error("Error in updating information.");
$this->response->redirect('user/profile');
} else {
echo "Great, a new robot was saved successfully!";
$this->flash->success("Member has been updaed successfully.");
//$this->response->redirect('user/profile');
}
Your isseue happens because you have already filled table and not yet properly defined model. Phalcon is validating all fo model data BEFORE trying to save it. If you define your model with all defaults, skips etc. properly, updates will be fired on single columns as you wish.
If you have definitions, that does not allow nulls, but you need an empty or default value there anyway, you may want to use 'beforeCreate' actions in model implementations. Also if there are things with defaults to set on first insert, you may wanto to use skipAttributes method.
More information is in documentation: Working with Models. So far best bit over internet I've found.
Also, below is an example for nullable email column and NOT NULL DEFAULT '0' 'skipped' column from my working code:
public function initialize() {
$this->skipAttributesOnCreate(['skipped']);
}
public function validation()
{
if($this->email !== null) {
$this->validate(
new Email(
array(
'field' => 'email',
'required' => true,
)
)
);
if ($this->validationHasFailed() == true) {
return false;
}
}
}
You do want errors of "something is required". All you're missing are just proper implementations of defaults over models. Once you get used to those mechanics, you should find them easy to handle and with more pros than cons.
What you are doing is called an insert. To set a column to a different value in a pre-existing row is called an update.
The latter is flexible, the former in not.
I highly recommend not treating a database like this is what i feel like
Put all the data in. Null is your enemy

How to add combined unique fields validator rule in Laravel 4

I am using Laravel 4.2 and mysql db . I have an exam table in which i am taking Exams entry and the fields are --> id | examdate | batch | chapter | totalmarks
I have made a combined unique key using $table->unique( array('examdate','batch','chapter') ); in schema builder.Now I want to add a validation rule to it. I know i can add unique validation by laravel unique validator rule but the problem is ,it checks only for one field . I want it to add uniqueness to the 3 fields combined(user must not be able to add second row with same value combination of examdate,batch and chapter fields).
Is it even possible to do it in laravel 4 .Is there any workaround if its not possible?
You could write a custom validator rule. The rule could look something like this:
'unique_multiple:table,field1,field2,field3,...,fieldN'
The code for that would look something like this:
Validator::extend('unique_multiple', function ($attribute, $value, $parameters)
{
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field)
$query->where($field, $value[$i]);
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
You can use as many fields as you like for the condition, just make sure the value passed is an array containing the values of the fields in the same order as declared in the validation rule. So your validator code would look something like this:
$validator = Validator::make(
// Validator data goes here
array(
'unique_fields' => array('examdate_value', 'batch_value', 'chapter_value')
),
// Validator rules go here
array(
'unique_fields' => 'unique_multiple:exams,examdate,batch,chapter'
)
);
It didn't work for me so I adjusted the code a tiny bit.
Validator::extend('unique_multiple', function ($attribute, $value, $parameters, $validator)
{
// Get the other fields
$fields = $validator->getData();
// Get table name from first parameter
$table = array_shift($parameters);
// Build the query
$query = DB::table($table);
// Add the field conditions
foreach ($parameters as $i => $field) {
$query->where($field, $fields[$field]);
}
// Validation result will be false if any rows match the combination
return ($query->count() == 0);
});
The validator looks like this. You don't need a particular order of DB table column names as stated in the other answer.
$validator = Validator::make($request->all(), [
'attributeName' => 'unique_multiple:tableName,field[1],field[2],....,field[n]'
],[
'unique_multiple' => 'This combination already exists.'
]);

Set a value to null, when calling Zend_Db::update() and insert()

My question is the exact same as How to Set a Value to NULL when using Zend_Db
However, the solution given in that question is not working for me. My code looks like the following. I call updateOper on the Model class when update is clicked on the front end. Inside updateOper, I call another function trimData() where I first trim all whitespace and then I also check that if some of the fields are coming in empty or '' I want to set them to default values or NULL values. Therefore I am using new Zend_db_expr('null') and new Zend_db_expr('default') .
The code is as follows:
private function trimData(&$data ) {
//Trim whitespace characters from incoming data.
foreach($data as $key => $val)
{
$data[$key] = trim($val);
if($data['notes'] == '') {
error_log("set notes to null/default value");
$data['notes'] = new Zend_db_expr('DEFAULT');
}
}
}
public function updateOper($data, $id)
{
$result = 0;
$tData = $this->trimData($data);
error_log("going to add data as ".print_r($data, true));
$where = $this->getAdapter()->quoteInto('id = ?', $id);
$result = $this->update($data, $where);
return $result;
}
The error_log statement prints the $data array as follows:
[id] => 10
[name] => alpha
[notes] => DEFAULT
As a result, the notes column has value ='DEFAULT' instead of picking the default value given in the table definition.
I have been trying to figure out what is wrong, but have not been able to find a solution.
I would really appreciate your help.
Thanks so much!
Your $data['notes'] is being changed to the __toString() value of the Zend_Db_Expr instead of preserving the actual object.
Maybe the reference is clogging things up. Else you may need to move the expression declaration into the actual update query.