Mapping field name in model using laravel - php

Is there a way to map field names to a database to a different attribute name in the model? For example, if the database has a field name of customer_id but I wanted to use eloquent in this way Customer::get(['id']) I've tried using the getAttribute method but that is called after eloquent has attempted to get the value.

You can use accessors to work with such attributes, but there's no way to query them this way with core eloquent.
But fear not! Use this package https://github.com/jarektkaczyk/eloquence and you can easily achieve what you want (Mappable in particular):
// Customer model
protected $maps =[
'id' => 'customer_id',
'name' => 'customer_name',
...
];
// then you can do this:
$customer = Customer::where('name', 'whatever')->first();
// calls WHERE customer_name = ? sql
$customer->id; // customer_id column
$customer->name; // customer_name column
$customer->name = 'different name'; // set mutator works as well
It's in heavy development and currently select is not yet supported, but it's matter of day or two. select support has been pushed already.

Related

Laravel Scout search by multiple columns

I have a user model with the following fields:
protected $fillable = [
'name',
'email',
'password',
'birthday',
'surname'
];
I created a search bar to search the users. I'm using Laravel scout to query the users like this:
$matchingUsers = User::search($request->search)->get();
If I search with just the name or just the surname, the result is fine. The problem is when introducing the name and the surname. In this case, I get no results.
Expected result
Given the following records in my database:
-[id=>1 , name => "Neil", surname => "Armstrong"]
-[id=>2 , name => "Juan Manuel", surname = "Armstrong"]
If I introduce "Neil Armstrong" I expect to get the user with id = 1.
If I search for "Juan Armstrong", I expect to get user with id = 2.
If I search for "Manuel", I expect to get the user with id = 2.
What I have tried so far
Using raw SQL directly querying in the database manager I got the expected result for situation 1 using the following query:
SELECT id, name, surname, image
FROM users
WHERE CONCAT(name,' ', surname) = "Neil Armstrong";
For the other two cases, I've tried to use the orWhere() method. However, this doesn't seem to work together, and anyway mixing raw SQL with eloquent and Scout seems so dirty.
Is there any way to use Laravel Scout to do something like this? A solution using just Eloquent wold also be useful.
By default, the database engine will execute a "where like" query against every model attribute that you have configured as searchable.
So in your case, name and surname are model attributes, and a query of "Neil Amstrong" will check both for %Neil Armstrong%. Nothing matches, so no results.
You can use an accessor to create a new fullName model attribute, and add that attribute to the toSearchableArray() method on your User model.
Create a fullName attribute for your User model.
UserAttributes.php
trait UserAttributes
{
public function getFullNameAttribute(): string
{
return $this->name." ".$this->surname;
}
}
Then in your User model's toSearchableArray() method, include the fullName attribute.
User.php
...
use UserAttributes;
public function toSearchableArray(): array
{
$searchable = [];
$searchable["fullName"] = $this->fullName;
// add more model attributes to search against...
return $searchable;
}
...
Now when you query "Neil Armstrong", the database engine will search the fullName attribute and find your user.
I've had the same problem, and eventually, I've completely removed Scout from my Laravel project and did it just with Eloquent:
$user_query = User::query();
$user_query->where(DB::raw('concat(name, " ", surname)'), 'like', $request);
$user = $user_query->get();
For the $request, I did:
$request = "%" . str_replace(" ", "%", request("query")) . "%";
With this, all three of the points you mentioned should be achieved.

Eloquent updateOrCreate hide columns while updating

I am using the updateOrCreate() function to update the record if a record is already available in the table based on some condition. However, I do not want to update one of my columns that contains a unique value.
I want to perform the same action to this column like created_at is working
while creating the records value is adding to the created_at column but while updating it contains the same.
To prevent this issue I removed that column name from $fillable in my model. But, in this case, it is not adding any value to this column.
protected $fillable = ['uid', 'channel', 'updated_at'];
$data = [
'uid' => Helper::generateUid(),
'channel' => $info['channel'],
'created_at' => time(),
'updated_at' => time(),
];
$cond = ['channel' => $info['channel']];
$isAdded = Templates::updateOrCreate($cond, $data);
Expected result
I don't want to update uid column if details already there.
Actual result
If details are not there it adds value to uid column and other columns also and if details are available then also it is updating uid column.
You can't do that with the updateOrCreate method. You'll need to be slightly more explicit. You can use the firstOrNew method to retrieve or instantiate a new object. And then you can use the exists property to determine if it is an existing or new object.
$template = Templates::firstOrNew(['channel' => $info['channel']]);
if (!$template->exists) {
$template->uid = Helper::generateUid();
}
$template->save();
I left out the created_at and updated_at fields because they are automatically handled by Laravel.

How to get last insert id in Eloquent ORM laravel

I am performing a database operation with "Eloquent ORM in Laravel". I just want to take the last insert id (not the maximum id) in the database.
I searched to get last insert id in laravel Eloquent ORM, I got following link (Laravel, get last insert id using Eloquent) that is refer to get last insert id from following function "$data->save()".
But I need to get
"Model::create($data)";
My Query:
GeneralSettingModel::create($GeneralData);
User::create($loginuserdata);
How can I retrieve the last inserted id?
Like the docs say: Insert, update, delete
"You may also use the create method to save a new model in a single
line. The inserted model instance will be returned to you from the
method. However, before doing so, you will need to specify either a
fillable or guarded attribute on the model, as all Eloquent models
protect against mass-assignment.
After saving or creating a new model that uses auto-incrementing IDs,
you may retrieve the ID by accessing the object's id attribute:"
$insertedId = $user->id;
So in your sample:
$user = User::create($loginuserdata);
$insertedId = $user->id;
then on table2 it is going to be
$input['table2_id'] = $insertedId;
table2::create($input);
**** For Laravel ****
$user = new User();
$user->name = 'John';
$user->save();
//Getting Last inserted id
$insertedId = $user->id;
You could wrap your data in the insertGetId() method like this
$id = DB::table('table')->insertGetId( $data );
In this case the array $data would look something like this
$data = [ 'field' => 'data' , 'field' => 'data' ];
and if you’re using the DB façade you could just append the lastInsertID() method to your query.
$lastInsertedID = DB::table('table')->insert( $data )->lastInsertId();
$lastId = User::create($loginuserdata)->id;
As others said bfore me you may retrieve id by using
$model->id;
but only if you are using standard naming convention for eloquent. If you want to use other name for primaryKey column, eg:
class Users extends Model{
$primaryKey = 'userid';
}
you may retrieve last inserted id by calling
$model->userid;
It is described in: https://laravel.com/docs/master/eloquent#eloquent-model-conventions where one can find:
Eloquent will also assume that each table has a primary key column
named id. You may define a $primaryKey property to override this
convention.
In addition, Eloquent assumes that the primary key is an incrementing
integer value, which means that by default the primary key will be
cast to an int automatically. If you wish to use a non-incrementing or
a non-numeric primary key you must set the public $incrementing
property on your model to false.
You may do it as,
public function store(Request $request,ModelName $obj)
{
$lastInsertedId = $obj->create($request->all())->id;
}
Hope this will help you.
This is my try:
$model_ins = Model::orderBy('id', 'desc')->take(1)->first();
And use $model_ins->id.
This code works with Laravel 5.3:
$upstatus = User::create($status);
return response()->json($upstatus);
User pages/site I was call data.id
This is an eloquent model:
$user = new Reports();
$user->email= 'david#example.com';
$user->save();
$lastInsertId = $user->id;
A solution using Query Builder:
$lastInsertId = DB::table('reports')->insertGetId(['email' => 'david#example.com']);
$user = (new user)->create($request->all()) ;
\Session::flash('message', 'Thanks , Your record No (' .$user->id . ') has been Successfully added');
This is my solution. I return the inserted object and get its ID or any other property.
This is an easier way that works on all of the ways that you inserted:
DB::getPdo()->lastInsertId()

Laravel Eloquent saving an object with children

I am trying to save an order with order_items but I am not really finding anything in the docs to support this use case. A hasMany relationship.
Basically there is an orders table with something like id | user_id and an order_items table with id | order_id | product_id.
How can I save() the order and use an array of items at the same time without having to loop over the items and save them individually?
Is this possible?
Pseudo code assuming $items is an array:
$items = Session::get("cart.items");
$order = new Order;
$order->user_id = Auth::user()->id;
$order->order_items = $items;
$order->save();
What you need for a hasMany relation is either saveMany or createMany, depending on what's in your $items array:
// array of attributes:
$items = [
['name'=>'item1','price'=>'price1'],
...
];
// then createMany:
$order->orderItems()->createMany($items);
This will create new rows in Items table.
// array of models:
$items = [
Item::find($someId),
Item::find($anotherId),
// and/or newly instantiated:
new Item(['name'=>'item1','price'=>'price1']),
...
];
// then createMany:
$order->orderItems()->saveMany($items);
This will associate (save) existing models, and create non-existing ones.
Also notice that I use camelCase relation name orderItems instead of your order_items.
This is an important detail, since Eloquent (Laravel v4) looks for camelCased methods on the model when working with relations (dynamic properties).
//Order model
public function orderItems()
{
return $this->hasMany(...);
}
$order->orderItems; // collection
$order->order_items; // collection as well
// --------------------
// BUT
public function order_items()
{
return $this->hasMany(...);
}
$order->orderItems; // null
$order->order_items; // null
// the only way you can work with relation then, is explicitly use method like:
$order->order_items()->get();
Probably not the best solution you are looking for, but this should work.
Let's say that the array is named $items, I'm under the impression that you will be saving it into a pivot table. In my example below I also have a 3rd field on item_order pivot table named item_quantity.
foreach ($items as $item)
{
$order->items()
->attach($item['item_id'], ['item_quantity' => $item['item_quantity']]);
}
Basically you will be looping through the $items array. This will assume that you have defined the relationship on your Order model called items().
Then use the attach() method
->attach([insert the item_id], array('3rd field name' => 'value to be inserted')
Finally, if you don't have a 3rd field on your pivot table you could just do
->attach($item_id)
You can check the example given at the Laravel docs
Note
attach() is the method used when the you are only creating a record on the Database, otherwise you need a different method when you want to update.
#jareks answer helped in a similar scenario except for a mass assignment exception . so on digging up docs i found that you need to set a guarded or fillable property for mass assignment in latest versions of laravel (4.2) .
please refer this along with his answer .
Fillable or guarded properties
When creating a new model, you pass an array of attributes to the model constructor. These attributes are then assigned to the model via mass-assignment. This is convenient; however, can be a serious security concern when blindly passing user input into a model. If user input is blindly passed into a model, the user is free to modify any and all of the model's attributes. For this reason, all Eloquent models protect against mass-assignment by default.
So set the fillable or guarded properties on your model. Docs and Source
class User extends Eloquent {
protected $fillable = array('first_name', 'last_name', 'email');
}

Creating new record and relationships in one go

I have the following basic schema:
players
id
name
profiles
id
player_id
email
subsets
id
profile_id
alias
I was under the impression the following operation was possible when creating a new record:
Player::create([
'name' => 'Player 1',
'profile.email' => 'player1#email.com',
'profile.subset.alias' => 'Player 1 alias'
]);
Since this code doesn't seem to work, is there anyway to save relationships records together with the create method?
Basically, you can't do this as easy as it looks.
In the docs, all related models are created after the base model is created
$profile = new Profile(array('email' => 'player1#email.com','alias'=>'Player 1 alias'));
$player = new Player(array('name'=>'Player 1'));
$player = $post->profile()->save($profile);
However , if you really want to do it in one go, you can overwrite the save() method in the Player model :
public function save(){
Database::transaction(function() {
$profileModel = new Profile($this->profile);
parent::save();
$this->profile()->insert($profileModel);
});
}
You will then pass the array to the Player method like :
array(
name='Player name',
profile=>array(
email=>'player1#email.com',
subset=>array(
alias=>'Player 1 alias'
)
);
Although this is not a recommended action.
Please read more about how to save the Eloquent models and relationships :
Tutorial 1
Tutorial 2
Everywhere is suggested to create the base model first, then the related models.

Categories