Laravel Eloquent firstOrCreate doesn't work properly - laravel

I'm used to it but today this problem makes me weak..;;
class Market {
// ..
public function ttl()
{
return $this->ttlRelation()->firstOrCreate(
['market_id' => $this->id],
['tier' => 0, 'direction'=>0]
);
}
}
The Market model has one TTL model. I know that firstOrCreate method finds an item as first given array and if it doesn't exists create a new one as persist, returns it.
Besides, its mass-assignment so I filled up $fillable property on ttl model..
class TradingTacticalLayer extends Model
{
public $timestamps = false;
protected $fillable = ['direction', 'tier'];
}
..and I'm getting SQLSTATE[HY000]: General error: 1364 Field 'direction' doesn't have a default value (SQL: insert into "trading_tactical_layer_test" ("tier", "market_id") values (0, 1)) message. I cannot understand why this method won't filled up insert field list proper way. I expect, if I edit $fillable property as ['direction'], SQL would implode ("direction") as insert field and it doesn't.
In general, from my experience, I just set those fields as nullable or manually set a default value. At this time, I want to know why this weird happens and what am I doing wrong.

Well, probably, optimize:clear solve the problem.
I still don't know what makes this error but if you experience mismatch between $fillable property and inserting field list, optimize:clear is an option anyway..

Related

Laravel updateOrCreate ignores 1 field

I have the following updateOrCreate:
protected $fillable = ['type', 'token', 'expires_on'];
$access = Ebaytoken::updateOrCreate(
['type' => 'access_token'],
['token' => $request->access_token, 'expires_on' => $request->access_token_expires_on]
);
However it gives this error:
SQLSTATE[23000]: [Microsoft][ODBC Driver 17 for SQL Server][SQL Server]Cannot insert the value NULL into column 'type', table 'toolkit.dbo._ebaytokens'; column does not allow nulls. INSERT fails. (SQL: insert into [_ebaytokens] ([token], [expires_on], [updated_at], [created_at]) values (access token goes here, 2020-03-09 09:01:02, 2021-07-12 14:18:31.031, 2021-07-12 14:18:31.031))
It's ignoring the type column in my query.
What have I done wrong here?
You have defined your own constructor on your model which is not its default constructor it gets from the Model class. The constructor on Model takes the attributes as an array and fills them on the instance. This way you can create a new instance of a Model with attributes. This is the important part of that constructor:
public function __construct(array $attributes = [])
{
...
$this->fill($attributes);
}
Without that you wouldn't be able to create a new Model instance with attributes filled.
This is what updateOrCreate is doing:
public function updateOrCreate(array $attributes, array $values = [])
{
return tap($this->firstOrNew($attributes), function ($instance) use ($values) {
$instance->fill($values)->save();
});
}
It is retrieving by the attributes or creating a new instance with the attributes (first argument). Eventually down those method calls you get to Model::newInstance which is doing this:
$model = new static((array) $attributes);
So without that constructor it can't create that new instance of the Model with those attributes, which in this case because of calling updateOrCreate is the first array you pass to updateOrCreate. It can fill the instance with the second array though as that is just a call to fill on the Model instance.
I would suggest to not override the constructor on a Model but if you really need to you could show what you are trying to do and perhaps you could get some advice or ideas on how to go about it.

Why is Laravel eloquent returning empty

This is my model
namespace App\Models\Invitation;
use App\Models\Model;
class SendtoType extends Model
{
}
When i get data from SendtoType it return empty or null but i sure sendto_types table has datas
$types = SendtoType::all();
dd($types); // return empty collection
$types = SendtoType::find(1);
dd($types);// null
It's happend after i run php artisan command:reset_table sendto_types command.
I cleared cache but it's not working.
Thank you everyone, i found my mistake:
i set timestamp for table's deleted_at column but forgot to set not null so it also filled deleted_at column when i add data.
That's why eloquent clause return empty.
So silly mistake!
You can add protected $table = 'sendto_types'; inside your model class with actual table name in your database.
class SendtoType extends Model
{
protected $table = 'sendto_types';
}
Command command:reset_table is not a built in command, so you'd need to look at your source code to see what it does, but by the name of it, I would assume the command empties your table.
In this case, your table is empty, so your query will not return any results.

Why eloquent doesn't return error on diffrent primarykey?

I was working on an old database which primarykey is 'Id'. Eloquent set up the primary key to default 'id', so it is little change, but still can be confusing. Of course I didnt notice that, and I wanted to save updated models to database. There was no error, and $model->save() return was good but database didn't update. Furthermore I have other functions that get models from the database, and they work as they should without overriding $primarykey.
So here is my question: Why isn't eloquent returning any warnings or errors ? Of course I found in the documentation that I should override $primarykey in the model, and then everything worked perfectly.
I was using MySql 10.1.16-MariaDB.
Here is Laravel controller
public function update(Request $request, Order $order)
{
$order->fill($request->get('data'));
$order->save();
$order->products;
return $order;
}
Vue.js function
editOrder () {
this.fullscreenLoading = true
axios.put('/web/' + this.url + '/' + this.rowId, {'data': this.row})
.then(({data}) => {
this.row = data;
this.fullscreenLoading = false
});
},
Laravel Model was standard, of course my model is now properly updated, when i got this problem there was no $primarykey, I didnt mention $fillable and relationship to products but in my project they are defined and working.
class Order extends Model
{
use LogsActivity;
protected $table = 'orders';
protected $primaryKey = 'Id';
protected $fillable = []
}
If you execute the query with get(), create() or similar method, it will work as before because Eloquent doesn't use PK in this case. But some methods like find() will not work for you until you setup $primaryKey property in the model.
You didn't get an error because there was no error.
When you ran $order->save(), the query generated would have been something like:
update `orders` set `field1` = ?, `fieldN` = ?, `updated_at` = ? where `id` is null
This is a perfectly valid SQL statement, and when it runs, it would produce no errors. However, it will also not update any records (unless you do have a record where the id is null).
The reason why the update query is using null is because your Order model does not have an id attribute, it has an Id attribute, and PHP array keys are case-sensitive. So, when Laravel attempts to get the value for the id attribute, it returns null, and uses that in the query.

Model returns relation´s dynamic attributes but null relation

I have set 2 models (Post and Category) with it´s proper relationships configured
class Post extends Model
{
protected $fillable = [
'title',
'excerpt',
'body',
'featured',
'published',
'category_id',
];
public function category()
{
return $this->belongsTo('App\Category');
}
}
class Category extends Model
{
protected $fillable = [
'name',
];
public function posts()
{
return $this->hasMany('App\Post');
}
}
And my Post´s storing method is
public function store(Request $request)
{
$post = Post::create($request->all());
return redirect('admin/posts');
}
The thing is, it´s actually working ok, it sets the category_id on the table and I can fetch all the dynamic data by using $post->category->name, but when I var_dump($post->relation) I get a null return.
I if create a new Post model, set all the attributes, save it and then associate the Category model (as documented on the official channel), it will return everything as expected.
For now, all I need is to fetch it´s dynamic attributes, and it´s working fine now, but I know I must be doing something wrong to get the null response. My concern is that it may be working fine now, but when the project gets larger I´ll probably face a bigger problem and I´ll have a lot of work to fix this issue.
The relation isn't there because you haven't loaded it. All it knows is the foreign key. It would be wildly inefficient if it grabbed all that information for you because it wouldn't always need all that. Think of instances where a single model could have many relationships, that would be many database calls for no reason.
If you need the relation, you can use $post->category. Since the relation is not yet loaded, it will get it for you when you do this.
Or you can eager load it by using the following $post->load('category') although this doesn't really benefit you because you are working with a single Post at this point. If you had a collection of Post objects, then you'd start seeing the benefits of using $posts->load('category') otherwise you end up with the n + 1 problem.
Consequently, if you use $post->load('category') and then var_dump($post), you should see that the relation is no longer null.

Return Eloquent model with different name from database tables

I want to return a JSON of an Eloquent model, but I'd like to change the array keys. By default they are set as the table field names, but I want to change them.
For example if I have a users table with two fields : id and user_name
When I return User::all(); I'll have a JSON with "[{"id" => 1, "user_name" => "bob}] etc.
I'd like to be able to change user_name to username. I haven't found the way to do it without an ugly foreach loop on the model.
I'm not sure why you would want to do this in the first place and would warn you first about the structure if your app/would it be better to make things uniform throughout.. but if you really want to do it.. you could do:
$user = User::find($id);
return Response::json(array('id' => $user->id, 'username' => $user->user_name));
That will return a JSON object with what you want.
You can also change the name of the key with:
$arr[$newkey] = $arr[$oldkey];
unset($arr[$oldkey]);
Just have a look at robclancy's presenter package, this ServiceProvider handles those things you want to achieve.
GITHUB LINK
Just set the $hidden static for you model to the keys you want to hide:
class User extends Eloquent
{
public static $hidden = 'id';
}
and name them the way you like with get and set functons.

Resources