I'm using Laravel 5.7 and PHP 7.3 where
I have to store decimal fields in database
table column decription look like this
'commission_percentage', 'decimal(12,4)'
'commission_amount', 'decimal(12,4)'
And I'm trying to store decimal value for this column in mysql using eloquent model.
And here is the example code for that.
$per = 10.23;
$commission = 2.1234;
$createArr = [
'commission_percentage' => $per,
'commission_amount' => $commission
];
MyModel::create($createArr);
my eloquent model look like
class MyModel extends Model
{
protected $table = 'my_table';
protected $guarded = ['id'];
protected $casts = [
'commission_percentage' => 'decimal:4',
'commission_amount' => 'decimal:4'
];
}
And I have also tried
protected $casts = [
'commission_percentage' => 'float',
'commission_amount' => 'float'
];
But no luck. I still get 10.0000 and 2.0000 inside the DB.
Even I have tried inserting value's using raw query
DB::insert('insert into my_table (commission_percentage,commission_amount ) values(?, ?)', [$per, $commission]);
But hard luck on that too as I still get 10.0000 and 2.0000 inside the DB.
The work around that I have found for this is to typecast the variable into "string"
$per = 10.23;
$commission = 2.1234;
$createArr = [
'commission_percentage' => (string) $per,
'commission_amount' => (string) $commission
];
MyModel::create($createArr);
Related
In my Laravel/Lumen Project (Version 8) I try to retrieve data from my Oracle Database, but I get unexpected data.
My database contains following 4 entries:
ID
FOREIGN_ID
NAME
1
100
Entry1
2
100
Entry2
3
100
Entry3
4
200
Entry4
My model:
class Entry extends Model
{
protected $connection = 'MyConnection';
protected $table = 'MY_TABLE';
protected $fillable = ['foreign_id', 'name'];
protected $hidden = ['foreign_id'];
protected $casts = [
'foreign_id' => 'integer'
];
}
When I execute the following line of code, only Entry1 with ID 1 is returned, while I would expect an empty collection:
Entry::where([['id', '!=', 1], 'foreign_id' => 100, 'name' => 'Entry1'])->get();
To analyze the problem, I also tried to write lined up where clauses:
//returns all but Entry1; correct
Entry::where(['id', '!=', 1])->get();
//returns Entry2 and Entry3; correct
Entry::where(['id', '!=', 1])->where(['foreign_id' => 100])->get();
//returns only Entry1; wrong, should be an empty collection
Entry::where(['id', '!=', 1])->where(['foreign_id' => 100])->where(['name' => 'Entry1'])->get();
The generated sql query looks like this:
"select * from "MY_TABLE" where ("ID" != ? and "FOREIGN_ID" = ? and "NAME" = ?)"
The Lumen Version is: 8.3.4
EDIT:
I have tried this on another Laptop now. There I get an empty collection.
Have you any idea what configuration/setting might do the trick, that my query is interpreted in two different ways?
Try below Code
Entry::where([
['id', '!=', 1],
['foreign_id', 100],
['name', 'Entry1']
])->get();
Is there a clean way to do a composite WHERE ... IN () condition with Eloquent/laravel.
The query result would be :
SELECT * FROM `table` WHERE (relation_type, relation_id) IN (('App\\Model', 1),('App\\Model', 3))
As you can see, that would be helpful for a single query fetch of an entity with polymorphic relation linked to 5 other models.
My current solution would be pure MySQL:
//Example :array of array with Model name & id
$couples = [
['relation_type' => 'App\\Model', 'relation_id' => 1],
['relation_type' => 'App\\ModelTwo', 'relation_id' => 2],
['relation_type' => 'App\\ModelThree', 'relation_id' => 5],
['relation_type' => 'App\\ModelTwo', 'relation_id' => 20],
//...
['relation_type' => 'App\\Model', 'relation_id' => 999],
];
$query = "SELECT * FROM table WHERE ('relation_type', 'relation_id') IN (("
.implode('),(', array_map(function ($entry) {
return "'".$entry['relation_type']."',".$entry['relation_id']; //I know , in relation_type the '\' needs to be escaped.
}, $couples))
."))";
$results = \DB::select($query);
}
Firstly you are able to put in DB::raw in both column and value, this will solve the problem of getting the SQL query correct, i tested the following on MySql 5.7 and it works. Db::raw just adds raw strings to the query, can be dangerous with injections.
->whereIn(DB::raw('(relation_type, relation_id)'), [DB::raw("('App\\Model', '2')")])
Now we just need to convert your array into that structure, my approach was a array_map foreach can also do the trick.
$couples = array_map(function ($item) {
$type = $item['relation_type'];
$id = $item['relation_id'];
return DB::raw("('$type', '$id')");
}, $couples);
Then call it with a simple Laravel query and you should be good to go.
$models = Model::whereIn(DB::raw('(relation_type, relation_id)'), $couples)->get()
I have 3 models:
Match Team Player
And i want to create a table with the following structure:
id | match_id | team_id | player_id
So that i can associate the 3 models i refered.
I created a 4th model MatchPlayers for the table i referred and I can use the 'search' functions without a problem. Like this:
$match->matchPlayers()->first()->team()->get()
And it returns the excpected result, but I cant do a
$match->matchPlayers()->sync([])
So, how should i solve this? Is my relationship wrong or the sync method isnt allowed on a 3 model relationship and I shoud use other method?
Thanks in advance
Edit:
Match.php
public function teamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Team.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
Player.php
public function matchTeamPlayers(){
return $this->hasMany('\Modules\Matchs\Entities\MatchPlayer');
}
MatchPlayer.php
public function player(){
return $this->belongsTo('\Modules\Players\Entities\Player');
}
public function match(){
return $this->belongsTo('\Modules\Matchs\Entities\Match');
}
public function team(){
return $this->belongsTo('\Modules\Teams\Entities\Team');
}
If you've followed the Laravel documentation on Pivot tables and Many-Many relationships found here, and it's still not working, you might have more luck with "Attach". For example;
$matchPlayer = MatchPlayer::create([...]);
$match->matchPlayers()->attach($matchPlayer)
A good example of sync vs attach can be found here
Using a fourth model for this kind of relationship makes sense, as it gives you a navigation property for the third relation on your pivot table. This way you can form more complex queries this way.
For your particular problem, syncing based on match_id and team_id, I would simply do something like this:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// remove all previously stored connections
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->delete();
// insert the news ones
// (you could also use MatchPlayer::create() per item or
// $matchPlayer->save(), it doesn't matter)
MatchPlayer::insert($rows);
If this operation occurs very frequently, you will potentially burn through a lot of id values of the pivot table. In this case you could also perform a more efficient sync, which is slightly more complex:
$matchId = 123;
$teamId = 234;
$rows = [
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 345],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 346],
['match_id' => $matchId, 'team_id' => $teamId, 'player_id' => 347],
];
// delete all players that are not among the new data anymore
MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->whereNotIn('player_id', array_pluck($rows, 'player_id'))
->delete();
// remove rows from new data that already exist
$exist = MatchPlayer::where('match_id', $matchId)
->where('team_id', $teamId)
->pluck('player_id')
->toArray();
$rows = array_filter($rows, function ($value, $key) use ($exist) {
return ! in_array($value['player_id'], $exist);
});
// then we store the remaining data
MatchPlayer::insert($rows);
Does Laravel / Eloquent provide a way to create multiple records with one call, if only one field is provided as an array?
For example I got $request coming in with data below, but only propIds will be exploded and provided as an array, all other values will be the same for the all new records.
{"_token": "kEKmrPzu4nCk35xJAMOgdl0kNdwUZvpECsBl91dH",
"propIds": "126,129,71,82,77,64,69",
"rate": "4",
"cost": "55"
}
I could do a foreach and build an array and then run Model::insert($newArray);
But maybe Laravel does provide a solution for if only one field is provided as an array. Thanks.
For now I am just using foreach loop to create array and then call Model::insert($newArray);
Inserting multiple records with Model::insert($newArray); will not automatically add created_at and updated_at dates. I added a timestamp as default value in the database.
Yes, it's possible. You need to use insert() and create a new array with this format:
Model::insert([
['prop_id' => 126, 'rate' => 4, 'cost' => 55],
['prop_id' => 129, 'rate' => 4, 'cost' => 55],
['prop_id' => 71, 'rate' => 4, 'cost' => 55],
]);
insert() will create just one DB query.
You can override Laravel Models create function like below :
Model
namespace App\Models;
class YourModel extends BaseModel
{
protected $fillable = [
"_token", "propId", "rate", "cost"
];
// override
public static function create(array $attributes = [])
{
$propIds = array_explode(',', $attributes['propIds']);
foreach ($propIds as $key => $value) {
$model = new static([
"_token" => $attributes['_token'],
"propId" => $value,
"rate" => $attributes['rate'],
"cost" => $attributes['cost']
]);
$model->save();
}
}
}
Controller
YourModel::create([
"_token" => $request->input('_token'),
"propIds" => $request->input('propIds'), // "126,129,71,82,77,64,69"
"rate" => $request->input('rate'),
"cost" => $request->input('cost'),
]);
I would like to make an associative array using PHP for loop to use in Yii2 map() method.
The array will look like in bellow format-
$listArray = [
['id' => '1', 'name' => 'Peter/5'],
['id' => '2', 'name' => 'John/7'],
['id' => '3', 'name' => 'Kamel/9'],
];
The id and name will be changed through each iteration of the loop. Here, the name will always hold customized value after some calculation inside the loop.
Finally, the list will be used in map() method like as following
$listData=ArrayHelper::map($listArray,'id','name');
I can use map() method directly after using the Active Record to find the list array and then use that in map() method. But it does not a give me way to use custom value for the name attribute.
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData=ArrayHelper::map($listArray,'id','name');
How can achieve this? Direct source code example would be really great for me.
Thanks in advance.
I'm assuming you want to query an ActiveRecord for data then transfer the data into a simple array.
$listData = [];
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
foreach($listArray as $user){
$customName = $user->name . $this->someCalculation();
$listData[] = ["id" => $user->id, "name" => $customName];
}
Or you could use the ArrayHelper class like this:
$listArray = UserList::find()
->where(['status' => 1])
->orderBy('name')
->all();
$listData = ArrayHelper::toArray($listArray , [
'app\models\UserList' => [
'id',
'name' => function ($listArray ) {
return $listArray->word . strlen($listArray->word); // custom code here
},
],
]);
I think the preferred way of doing this by defining custom calculation rule in UserList model as:
public function getCustomRuleForUser(){
// Do what ever you want to do with your user name.
return $this->name.'Your custom rule for name';
}
And use as:
$userList = UserList::find()->all();
$listData=ArrayHelper::map($userList,'id','customRuleForUser');
Now, you have your custom rule for username list in $listData.
$model_userprofile = UserProfile::find()->where(['user_id' => Yii::$app->user->id])->one();
$model_userprofile1 = UserProfile::find()
->select('user_id')
->where(['group_id' => $model_userprofile->group_id])->all();
$listData = [];
foreach($model_userprofile1 as $user){
$id = $user->user_id;
$listData[] = ["id" => $id];
}
$dataProvider = new ActiveDataProvider
([
'query' => User::find()
->select('id,username,email')
->Where(['id' => $listData])
->orderBy(['id' => SORT_DESC]),
'pagination' => ['pagesize' => 15]]);
return $this->render('index',['dataProvider'=> $dataProvider]);