Laravel Eloquent - php

When I try to fill my database using the model method create like this:
public function registerDevice($command) {
$deviceId = $command->deviceId;
$deviceToken = $command->deviceToken;
$this->deviceId = $deviceId;
$this->deviceToken = $deviceToken;
Device::create(array('device_id' => $deviceId, 'device_token' => $deviceToken));
$this->raise(new DeviceWasRegistered($this));
return $this;
}
The entry is being made, but only the timestamps are being updates. The value fields are empty. No error coming up or something else is failing. But the values I want to put into the db are there if I var_dump the variables.
Do I miss something out?

In order for the create method to work, you need to put your two fields in the $fillable array on the model. So make sure you have this in your model:
protected $fillable = [
'device_id',
'device_token',
];
You can read more about the create method and mass assignment at http://laravel.com/docs/5.1/eloquent#mass-assignment.

Related

Laravel - Data is not being displayed using a all

Using the code below resulting in an empty array
$data = M_Obat::all();
While using the code below resulting in an array containing 2 data
$data = DB::table('master.ruangan')->get();
Attached images:
[1]: https://i.stack.imgur.com/KSc9Z.png
[2]: https://i.stack.imgur.com/wBylo.png
probably your model (M_Obat) is not correctly related to the right table:
try to specify it in your model class:
protected $table = 'master.ruangan';
check your model for 'hidden'
if a variable called $hidden is declared in model, fields added in it will not be shown.
protected $hidden = [
'password',
'remember_token',
];
$data = M_Obat::all()
Data that you want it exists in #attributes

Laravel : Get all columns except some of them [duplicate]

When I'm using eloquent, I can use the "where" method then the method 'get' to fill an object containing what I've selected in my database.
I mean:
$users = User::where('gender', 'M')->where('is_active', 1)->get(['pseudo', 'email', 'age', 'created_at'])->toArray();
Here I can choose the columns I want to get like 'pseudo', 'email', etc..
But what I miss in laravel doc is the way to do the contrary.
It could be something like that:
$users = User::where('gender', 'M')->where('is_active', 1)->notGet(['pseudo', 'email', 'age', 'created_at'])->toArray();
Thank you for you futur answer and have a nice day.
If you only need to hide attributes from your model's array or JSON representation, you may use one or both approaches:
Add the
$hidden property to your model
class User extends Model
{
/**
* The attributes that should be hidden for arrays.
*/
protected $hidden = ['password'];
}
Use the
makeHidden
function
$users = $users->makeHidden(['address', 'phone_number']);
See other answers for more details... But sometimes you don't want to load huge data (geospatial, html, logs...) into your application, it will be slow and take more memory. OP asked for an SQL query hence my answer, but most of the time it's more convenient to only hide the data from the JSON response.
AFAIK there is no build in option in SQL to exclude columns explicitly, so Laravel can't do it. But you can try this trick
Update
Another trick is to specify all columns in your model (or use an extra query to get all columns using $this->getTableColumns() from this answer, it can also be cached after each migration to avoid two queries) then add a local scope function
// The below code requires you to define all columns in $columns.
// A better approach is to query the schema of the table and cache it after each
// migration, for more details: https://stackoverflow.com/a/56425794/3192276
protected $columns = ['id','pseudo','email'];
public function scopeExclude($query, $value = [])
{
return $query->select(array_diff($this->columns, (array) $value));
}
Then you can do :
$users = User::where('gender', 'M')
->where('is_active', 1)
->exclude(['pseudo', 'email', 'age', 'created_at'])
->toArray();
using hidden array in model is good, but if you don't want to hide your column all the time and use makeVisible to access them in need, then instead, hide your column from serialization where you need with makeHidden function like this :
$res = Model::where('your query')->get();
$res->makeHidden(['column_one','column_two','column_n']);
return response()->json($res);
I don't know about previous Laravel version, but in 5.4 you can put this line in User model
protected $hidden = ['pseudo', 'email', 'age', 'created_at'];
and then User::find(1); will return all fields except pseudo, email, age, and created_at.
But you still can retrieve those hidden fields by using:
$user = User::find(1);
$email = $user['email']; // or $user->email;
I have looked into the answer by #Razor
But there is Very Conveinent way by skipping $columns property
/**
* Scope a query to only exclude specific Columns.
*
* #author Manojkiran.A <manojkiran10031998#gmail.com>
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeExclude($query, ...$columns)
{
if ($columns !== []) {
if (count($columns) !== count($columns, COUNT_RECURSIVE)) {
$columns = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($columns)));
}
return $query->select(array_diff($this->getTableColumns(), $columns));
}
return $query;
}
/**
* Shows All the columns of the Corresponding Table of Model
*
* #author Manojkiran.A <manojkiran10031998#gmail.com>
* If You need to get all the Columns of the Model Table.
* Useful while including the columns in search
* #return array
**/
public function getTableColumns()
{
return \Illuminate\Support\Facades\Cache::rememberForever('MigrMod:'.filemtime(database_path('migrations')).':'.$this->getTable(), function () {
return $this->getConnection()->getSchemaBuilder()->getColumnListing($this->getTable());
});
}
getTableColumns function will get all the columns of the table so you dont need to define the $column property
NOTE: COLUMN NAMES OF TABLE WILL BE CACHED UNTIL CONTENTS OF MIGRATIONS DIRECTORY IS ADDED OR DELETED.
MODIFYING THE CONTENTS OF FILES INSIDE THE MIGRATIONS DIRECTORY WILL
NOT RE-CACHE THE COLUMNS
To clear cache manually you can run php artisan cache:clear
you can use hidden array like this:
class Promotion extends Model
{
protected $table = 'promotion';
protected $hidden = array('id');
}
I have a solution that worked for me, which is slightly different than those already stated.
Solution:
$all_columns = Schema::getColumnListing('TABLE_NAME');
$exclude_columns = ['COLUMN_TO_EXCLUDE_1', 'COLUMN_TO_EXCLUDE_2'];
$get_columns = array_diff($all_columns, $exclude_columns);
return User::select($get_columns)->get();
Reasoning:
For me:
Razor's answer didn't work as I got the following error:
BadMethodCallException with message 'Call to undefined method App/CaseStudy::exclude()'
Then, the remaining answers were attemping to hide the columns within the model. Unfortunately, that would hide them for each method in my class and this isn't something that I wanted.
So, in the end, I modified Razor's solution so that it would work without having to hide any of the columns for each method.
I hope this helps someone! 😊
We get the object eloquent from the model full with all fields, transform it to array and we put it inside of a collection. Than we get all fields except all fields specified in array $fields.
$fields = ['a', 'b', 'c', 'N'];
$object = Model::find($id);
return collect($object->toArray())->except($fields);
More clearly, let's give an example:
// Array of fields you want to remove
$fields_to_remove = ['age', 'birthday', 'address'];
// Get the result of database
$user = User::find($id);
// Transform user object to array
$user = $user->toArray();
// Create a collection with the user inside
$collection = collect($user);
// Get all fields of our collection except these fields we don't want
$result = $collection->except($fields_to_remove);
// Return
return $result;
This example above makes exactly the same thing of the first one, but it's more explained.
you can use makeHidden array like this: (After get() or all())
$users = User::where('gender', 'M')->where('is_active', 1)->get()->makeHidden(['pseudo', 'email', 'age', 'created_at'])->toArray();
You can leverage Illuminate\Support\Facades\Schema::getColumnListing('table_name');
use Illuminate\Support\Facades\Schema;
$users_table_columns = Schema::getColumnListing('users');
$exclude_columns = [
'password',
'token',
'address',
];
$select = array_diff($users_table_columns, (array) $exclude_columns);
$site = User::select($select)
->where('gender', 'M')
->where('is_active', 1)
->first();
I wrapped a slitly changed approach from #manojkiran-a up in a small package, cause I needed it in multiple projects:
https://github.com/laracraft-tech/laravel-useful-traits/#selectallbut
Install via composer:
composer require laracraft-tech/laravel-useful-traits
This is how it is working:
use LaracraftTech\LaravelUsefulTraits\UsefulScopes;
$class = new class extends Model
{
use UsefulScopes;
protected $timestamps = false;
protected $table = 'scope_tests';
};
$class->create([
'foo' => 'foo',
'bar' => 'bar',
'quz' => 'quz',
]);
$class::query()->selectAllBut(['foo'])->first()->toArray();
// return ['bar' => 'bar', 'quz' => 'quz']
Note: Since you can't do a native "select all but x,y,z" in mysql, we need to query (and cache) the existing columns of the table, and then exclude the given columns which should be ignored (not selected) from the existing columns.
Cache: Column names of each table will be cached until contents of migrations directory is added or deleted. Modifying the contents of files inside the migrations directory will not re-cache the columns. Consider to clear the cache whenever you make a new deployment/migration!
You can use unset unset($category->created_at,$category->updated_at);
$fcategory = array();
$kCategory = KCategory::where("enabled", true)->get();
foreach ($kCategory as $category) {
$subkCategory = PostCategory::select("id", "name", "desc")
->where("id_kcategory", $category->id)
->where("enabled", true)
->get();
unset($category->created_at, $category->updated_at);
$fcategory[] = $category;
}

Laravel 5.4 field doesn't have a default value

I am having this error and none of the googled result i checked is similar to my problem.
I have an application with class Deal, User, and Matches
A deal has many matches.
A user has many matches.
A user has many deals.
I am attempting to create a new Match using my Deal object
$deal->matches()->create(['user_id'=>$id]);
This is my match class, i have defined all needed relationships
class Match extends Model
{
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $guarded = [];
public $timestamps = false;
public $expired_on = "";
public static function boot()
{
parent::boot();
static::creating(function ($model) {
$model->matched_on = $model->freshTimestamp();
});
}
public function __construct(){
$d = (new \DateTime($this->matched_on))->modify('+1 day');
$this->expired_on = $d->format('Y-m-d H:i:s');
}
/**
* Get the user that owns the match.
*/
public function user()
{
return $this->belongsTo('App\User');
}
/**
* Get the deal that owns the match.
*/
public function deal()
{
return $this->belongsTo('App\Deal');
}
}
And i keep getting this error when i attempt to create a new match.
QueryException in Connection.php line 647:
SQLSTATE[HY000]: General error: 1364 Field 'user_id' doesn't have a default value (SQL: insert into matches (deal_id) values (1))
I have my guarded to be an empty array, what could be the problem?
Remove the guarded array and add the fillable instead:
protected $fillable = ['user_id', 'deal_id'];
If you would like to revert to previous behavior, update your
config/database.php
file and set 'strict' => false for your connection.
Since it was a unique field in my case, I could not make it nullable.
For me, I had an empty constructor which was causing the issue don't know why.
Please comment if anyone knows the reason.
public function __construct(){
}
Commenting/removing it resolved the issue.
If you have a constructor in your model, just make sure it has a call to a parent constructor as well:
public function __construct( array $attributes = array() ) {
// mandatory
parent::__construct($attributes);
//..
}
Otherwise, it will break some functionality like Model::create.
Alexey Mezenin's Answer is correct and a good one.
Another way i used around it, for those who want to maintain the guarded empty array is to create a new Match object and put in the attributes and save.
$match->user_id = $id;
$match->deal_id = $deal->id;
$match->matched_on = $match->freshTimestamp();
$match->save();
I am using Laravel 8 and fixed this error thorugh this two steps:
move the word from $guarded array to $fillable array in User Mode
Config.database.php: 'strict' => false in the array of 'mysql'
Another way around this error is to include
'strict' => false,
into config/database.php within mysql array
When manually importing / exporting the databases, check if the transfer of all table settings was successful. If you forget to add an auto increment primary key, Laravel doesn't fill the value for you.
Adding the AUTO_INCREMENT afterwards will solve the problem.
I had this error but my wrong was making class model:
$book = new Book();
While this is true
$book = new Book($request->all());
changing your "config/database.php" won't help.
If you're getting this error, you're not sending the data to database correctly.
check your function in your controller, the create() method is probably being blocked by an if statement or something.
or
if it's an API, check the post request from the frontend that's where your issue is.
make sure the form is correctly passed into to request.

How to exclude certains columns while using eloquent

When I'm using eloquent, I can use the "where" method then the method 'get' to fill an object containing what I've selected in my database.
I mean:
$users = User::where('gender', 'M')->where('is_active', 1)->get(['pseudo', 'email', 'age', 'created_at'])->toArray();
Here I can choose the columns I want to get like 'pseudo', 'email', etc..
But what I miss in laravel doc is the way to do the contrary.
It could be something like that:
$users = User::where('gender', 'M')->where('is_active', 1)->notGet(['pseudo', 'email', 'age', 'created_at'])->toArray();
Thank you for you futur answer and have a nice day.
If you only need to hide attributes from your model's array or JSON representation, you may use one or both approaches:
Add the
$hidden property to your model
class User extends Model
{
/**
* The attributes that should be hidden for arrays.
*/
protected $hidden = ['password'];
}
Use the
makeHidden
function
$users = $users->makeHidden(['address', 'phone_number']);
See other answers for more details... But sometimes you don't want to load huge data (geospatial, html, logs...) into your application, it will be slow and take more memory. OP asked for an SQL query hence my answer, but most of the time it's more convenient to only hide the data from the JSON response.
AFAIK there is no build in option in SQL to exclude columns explicitly, so Laravel can't do it. But you can try this trick
Update
Another trick is to specify all columns in your model (or use an extra query to get all columns using $this->getTableColumns() from this answer, it can also be cached after each migration to avoid two queries) then add a local scope function
// The below code requires you to define all columns in $columns.
// A better approach is to query the schema of the table and cache it after each
// migration, for more details: https://stackoverflow.com/a/56425794/3192276
protected $columns = ['id','pseudo','email'];
public function scopeExclude($query, $value = [])
{
return $query->select(array_diff($this->columns, (array) $value));
}
Then you can do :
$users = User::where('gender', 'M')
->where('is_active', 1)
->exclude(['pseudo', 'email', 'age', 'created_at'])
->toArray();
using hidden array in model is good, but if you don't want to hide your column all the time and use makeVisible to access them in need, then instead, hide your column from serialization where you need with makeHidden function like this :
$res = Model::where('your query')->get();
$res->makeHidden(['column_one','column_two','column_n']);
return response()->json($res);
I don't know about previous Laravel version, but in 5.4 you can put this line in User model
protected $hidden = ['pseudo', 'email', 'age', 'created_at'];
and then User::find(1); will return all fields except pseudo, email, age, and created_at.
But you still can retrieve those hidden fields by using:
$user = User::find(1);
$email = $user['email']; // or $user->email;
I have looked into the answer by #Razor
But there is Very Conveinent way by skipping $columns property
/**
* Scope a query to only exclude specific Columns.
*
* #author Manojkiran.A <manojkiran10031998#gmail.com>
* #param \Illuminate\Database\Eloquent\Builder $query
* #return \Illuminate\Database\Eloquent\Builder
*/
public function scopeExclude($query, ...$columns)
{
if ($columns !== []) {
if (count($columns) !== count($columns, COUNT_RECURSIVE)) {
$columns = iterator_to_array(new \RecursiveIteratorIterator(new \RecursiveArrayIterator($columns)));
}
return $query->select(array_diff($this->getTableColumns(), $columns));
}
return $query;
}
/**
* Shows All the columns of the Corresponding Table of Model
*
* #author Manojkiran.A <manojkiran10031998#gmail.com>
* If You need to get all the Columns of the Model Table.
* Useful while including the columns in search
* #return array
**/
public function getTableColumns()
{
return \Illuminate\Support\Facades\Cache::rememberForever('MigrMod:'.filemtime(database_path('migrations')).':'.$this->getTable(), function () {
return $this->getConnection()->getSchemaBuilder()->getColumnListing($this->getTable());
});
}
getTableColumns function will get all the columns of the table so you dont need to define the $column property
NOTE: COLUMN NAMES OF TABLE WILL BE CACHED UNTIL CONTENTS OF MIGRATIONS DIRECTORY IS ADDED OR DELETED.
MODIFYING THE CONTENTS OF FILES INSIDE THE MIGRATIONS DIRECTORY WILL
NOT RE-CACHE THE COLUMNS
To clear cache manually you can run php artisan cache:clear
you can use hidden array like this:
class Promotion extends Model
{
protected $table = 'promotion';
protected $hidden = array('id');
}
I have a solution that worked for me, which is slightly different than those already stated.
Solution:
$all_columns = Schema::getColumnListing('TABLE_NAME');
$exclude_columns = ['COLUMN_TO_EXCLUDE_1', 'COLUMN_TO_EXCLUDE_2'];
$get_columns = array_diff($all_columns, $exclude_columns);
return User::select($get_columns)->get();
Reasoning:
For me:
Razor's answer didn't work as I got the following error:
BadMethodCallException with message 'Call to undefined method App/CaseStudy::exclude()'
Then, the remaining answers were attemping to hide the columns within the model. Unfortunately, that would hide them for each method in my class and this isn't something that I wanted.
So, in the end, I modified Razor's solution so that it would work without having to hide any of the columns for each method.
I hope this helps someone! 😊
We get the object eloquent from the model full with all fields, transform it to array and we put it inside of a collection. Than we get all fields except all fields specified in array $fields.
$fields = ['a', 'b', 'c', 'N'];
$object = Model::find($id);
return collect($object->toArray())->except($fields);
More clearly, let's give an example:
// Array of fields you want to remove
$fields_to_remove = ['age', 'birthday', 'address'];
// Get the result of database
$user = User::find($id);
// Transform user object to array
$user = $user->toArray();
// Create a collection with the user inside
$collection = collect($user);
// Get all fields of our collection except these fields we don't want
$result = $collection->except($fields_to_remove);
// Return
return $result;
This example above makes exactly the same thing of the first one, but it's more explained.
you can use makeHidden array like this: (After get() or all())
$users = User::where('gender', 'M')->where('is_active', 1)->get()->makeHidden(['pseudo', 'email', 'age', 'created_at'])->toArray();
You can leverage Illuminate\Support\Facades\Schema::getColumnListing('table_name');
use Illuminate\Support\Facades\Schema;
$users_table_columns = Schema::getColumnListing('users');
$exclude_columns = [
'password',
'token',
'address',
];
$select = array_diff($users_table_columns, (array) $exclude_columns);
$site = User::select($select)
->where('gender', 'M')
->where('is_active', 1)
->first();
I wrapped a slitly changed approach from #manojkiran-a up in a small package, cause I needed it in multiple projects:
https://github.com/laracraft-tech/laravel-useful-traits/#selectallbut
Install via composer:
composer require laracraft-tech/laravel-useful-traits
This is how it is working:
use LaracraftTech\LaravelUsefulTraits\UsefulScopes;
$class = new class extends Model
{
use UsefulScopes;
protected $timestamps = false;
protected $table = 'scope_tests';
};
$class->create([
'foo' => 'foo',
'bar' => 'bar',
'quz' => 'quz',
]);
$class::query()->selectAllBut(['foo'])->first()->toArray();
// return ['bar' => 'bar', 'quz' => 'quz']
Note: Since you can't do a native "select all but x,y,z" in mysql, we need to query (and cache) the existing columns of the table, and then exclude the given columns which should be ignored (not selected) from the existing columns.
Cache: Column names of each table will be cached until contents of migrations directory is added or deleted. Modifying the contents of files inside the migrations directory will not re-cache the columns. Consider to clear the cache whenever you make a new deployment/migration!
You can use unset unset($category->created_at,$category->updated_at);
$fcategory = array();
$kCategory = KCategory::where("enabled", true)->get();
foreach ($kCategory as $category) {
$subkCategory = PostCategory::select("id", "name", "desc")
->where("id_kcategory", $category->id)
->where("enabled", true)
->get();
unset($category->created_at, $category->updated_at);
$fcategory[] = $category;
}

Laravel model insert - reduce code size

I know it is literally going to do nothing in terms of efficiency, but is there a simple way to condense this;
$customer = new Customer;
$customer->firstname = $data['f_name'];
$customer->lastname = $data['l_name'];
$customer->email = $data['email'];
$customer->phone_number = $data['phone'];
$customer->venue_id = Auth::user()->venue_id;
$customer->save();
Into just one line of code?
My models are getting real fat.
You may alternatively use create() method but not a big difference, for example:
$customer = Customer::create(array(
'firstname' => $data['f_name'],
'lastname' => $data['l_name'],
'email' => $data['email'],
'phone_number' => $data['phone'],
'venue_id' => Auth::user()->venue_id
));
To do this, you have to assign in your Customer model either
protected $fillable = array('firstname', 'lastname', 'email', 'phone_number', 'venue_id')
Or you may use opposite one
// Assumed you have an id and password field
protected $guarded = array('id', 'password');
Or you may use a blank to allow all fields
protected $guarded = array();
So, you may use mass assignment using create() method of your model. Since you have a $data array already available with populated inputs but field names are not matched with database table, so, if you can populate the $data variable using proper database field names then you may use that $data variable in the create() method.
Also, you may directly use Input something like this:
$inputs = Input::except('_token'); // all inputs without _token hidden field
Validate these inputs then insert like:
Customer::create($inputs);
Or you may delete any item from the array using unset($inputs['key']) if you have other values in $_post array and want to remove those fields before inserting/creating into database table. Read about Mass Assignment.
Use the fillable array as sheika suggested and ensure your input params match the models attributes. This is what it typically looks for me.
$model = Customer::create( Input::get() );
Or
$model = new Customer;
$model->fill( Input::get() );
$model->save();

Categories