Accessing to the `latest` record stored in DB table right after recording it - mysql

In Laravel After recording last row to a DB table, can I safely access same recorded data right after recording it by calling latest() queries? Because transactions by other users may occur at the same time, and it may not really be the last record anymore?
Edit:
For example:
Public function StoreNotif($data){
auth()->user()->Notif()->create(store $data here..)
}
Public function SendNotif(){
$data="123";
$this->StoreNotif($data)
event(new Notification(stored Notif instance?));
}

No, you cannot rely on the database to return the record from your current script.
The ->latest() method will always sort the records with the most recent created_at date first.
https://laravel.com/docs/6.x/queries#ordering-grouping-limit-and-offset
But you haven't provided any code or explanation as to why this is a concern. If you just created a new record, why do you need to query it again? You should already have access to an instance of the model.
EDIT: I've made a few edits to demonstrate how you would pass the model from a controller to an event as referenced in the comments. Please post your code if you want more specific help.
SomeController.php
function store()
{
$model = Model::create([
'some_data' => 1
]);
// fire an event with the newly created model
event(new SomeEvent($model));
dd($model);
}
------------------------
Model {
// ...
attributes: [
'id' => 101,
'some_data' => 1
'created_at' => '2019-10-06 12:48:01',
'updated_at' => '2019-10-06 12:48:01',
]
// ...
}
SomeEvent.php
<?php
namespace App\Events;
use App\Model;
use Illuminate\Queue\SerializesModels;
class SomeEvent
{
use SerializesModels;
public $model;
public function __construct(Model $model)
{
$this->model = $model;
// ...
}
}
EDIT: Per your newly added code, you just need to pass the new model back to the original method. You could do something like this.
Public function StoreNotif($data)
{
// add a return statement
return auth()->user()->Notif()->create(store $data here..);
}
Public function SendNotif()
{
$data="123";
// store the returned data to a variable
$model = $this->StoreNotif($data);
// call the event with the model instance
event(new Notification(model));
}

I'm not sure what 'latest' is but I do know that MySQL uses SELECT LAST_INSERT_ID as the query to get the 'per-connection' id of the last inserted item. Under the covers it's using mysql_insert_id so if you are in a language that supports it, you could use that too.

Related

Problem with getting data from tables in Yii2

I have created method in the Yii2 model Users to get all the replies for the current user
public function getAllRepliesForUsers() { return $this->hasMany(Replies::class, ['user_id' => 'id'])->viaTable('replies_links', ['replies_id' => 'id'])->where(['entity'=>'user']); }
My replies table
My users table
and the final table that links these two tables
Is my method is correct?
Here's the relationship of Users to the Replies. You can use the Model generator of Gii module so you won't get confused by manually typing them.
public function getReplies()
{
return $this->hasMany(Replies::className(), ['id' => 'reply_id'])->viaTable('rply_links', ['user_id' => 'id']);
}
(May I know what do you intend to do with the condition ->where(['entity'=>'user'])?).

How do I return a union as an Active Record object?

I have these union in my controller :
$expression = new Expression('"News"');
$featuredNews2= news::find()
->alias('ne')
->select(['ne.title', 'ne.content','ne.featuredOrder', 'category'=>$expression])
->innerJoinWith('featuredOrder1');
$expression2 = new Expression('"Event"');
$featuredEvents2 = event::find()
->select(['ev.title', 'ev.content','ev.featuredOrder','category'=>$expression2])
->from('event ev')
->innerJoinWith('featuredOrder2');
$union = $featuredNews2->union($featuredEvents2);
The relation in model :
news model
public function getFeaturedOrder1()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
event model
public function getFeaturedOrder2()
{
return $this->hasOne(Featured::className(), ['featuredOrder' => 'featuredOrder']);
}
I need to return the query as an Active Query because I need to access my model's method e.g : $model->featuredOrder1->preview in my view.
The following works but it returns an array, as the result I can't access my model's method :
$unionQuery = (new \yii\db\Query)->select('*')
->from($union)
->orderBy('featuredOrder')->all(\Yii::$app->db2);
I have two questions :
How to return the equivalent $unionQuery above but as an active query object? I have googled and search on SO but what I found is how to return it as array.
This is out of curiosity, I wonder why I should provide my db connection as argument in my $unionQuery all() method above. If I didn't use an argument that point to db2, it will look for table name inside my db database instead ( db is my parent database, this db2 is my module's database/the correct one). This only happen with a union. My news and event model already have this in getdb() function:
return Yii::$app->get('db2');
update
I've tried this too :
$unionProvider = (new ActiveQuery(Featured::className()))->select('*')
->from(['union' => $featuredEvents2->union($featuredNews2)])
->orderBy('featuredOrder');
With this relation in featured model:
public function getNews()
{
return $this->hasOne(News::className(), ['featuredOrder' => 'featuredOrder']);
}
public function getEvents()
{
return $this->hasOne(Event::className(), ['featuredOrder' => 'featuredOrder']);
}
and in the view, I tried this :
foreach($unionProvider as $key=>$model){
echo $model->news->title;
}
but get this error : Trying to get property of non-object
Update 2
I forgot to add ->all() in my $unionProvider, but after that I got this error instead : PHP Fatal Error – yii\base\ErrorException
Allowed memory size of 134217728 bytes exhausted (tried to allocate 12288 bytes)
Might be something wrong with my query? Can't figure it out
You can try using pure SQL. Plus you can test to see if it is returning the correct results and then add it in the statement below.
$customers = Customer::findBySql('SELECT * FROM customer')->all();
Learn more in yii docs

Integers are marked as dirty attributes no matter what

I need to check if a model has been updated and what attributes have changed when saving.
I'm using dirtyAttributes and filter intval as the docs suggests.
The values are coming from an API and are type-cast as they come in, so in theory the filter is redundant.
Model rules
public function rules()
{
return [
[['contract_date', 'order_date'], 'integer'],
[['contract_date', 'order_date'], 'filter', 'filter' => 'intval'],
];
}
This is some of the code currently running:
// Add the changed status variables to the job log
$dirty_attributes = array_keys($model->dirtyAttributes);
if($model->save()) foreach ($dirty_attributes as $attribute)
{
$data[$attribute] = $model->getOldAttribute($attribute).' ('.gettype($model->getOldAttribute($attribute)).')'. ' => '. $model->$attribute.' ('.gettype($model->$attribute).')';
}
var_dump($data);
This produces:
["contract_date"]=>
string(44) "1559669638 (integer) => 1559669638 (integer)"
["order_date"]=>
string(44) "1559669638 (integer) => 1559669638 (integer)"
There is probably something obvious I'm missing, but I can understand what.
After saving model all "oldAttributes" are updated to store new values so comparing them like you do makes no sense. If you want to check which attributes have been changed after saving you can override afterSave() method in your model like:
public function afterSave($insert, $changedAttributes)
{
// $changedAttributes -> this is it
parent::afterSave(); // call parent to trigger event
}
or listen for ActiveRecord::EVENT_AFTER_INSERT / ActiveRecord::EVENT_AFTER_UPDATE event where this data is also passed.

Expanding this method to write to the database

Hi I followed a tutorial to implement a friend system. It all works find, but I need to post other columns to the row that just the id's. How would I expand that.
This is the method that is accessed when the add friend button is clicked
public function getAdd($id){
$user = User::where('id', $id)->first();
//After passing all checks. Add other account
Auth::user()->addFriend($user);
echo "Sent";
}
AddTenancy Method
public function addFriend(User $user){
$this->friendsOf()->attach($user->id);
}
I assume the relationship is many-to-many between users. And you need to add additional data to the pivot.
Here's how you'd do that:
public function addFriend(User $user){
$this->friendsOf()->attach($user->id, ['another_col' => 'some data']);
}
Replace 'another_col' and some data with your column and your data. You can also add more than 1 column into the array.

Insert a field with value whenever new instance of modal is created

I want to insert a field with value whenever new row is created for a modal.
Ex: Suppose this is my user.php modal
class User extends Authenticatable
{
protected $guarded = ['id'];
}
What i want is in my application anywhere when i insert a row in user table, then i want to insert an extra column code with its value in user table.
Ex: If i do below in my application
User::create(['name'=>'xyz', 'password' => 'kajsndjk']);
then it should insert an extra column code =>'Qwedf' also in my table.
In my application there are many places where i am creating the users, so i don't want to remember every time to insert code column.
Please suggest how can i achieve it.
Overriding the static create function on the User class is the only thing that will work in my opinion.
public static function create(array $attributes = [])
{
$object = parent::create($attributes);
$object->code = 'some text';
$object->save();
return $object;
}
I've tested and like I expected, oseintow's answer will not work, because it would work only if you directly modified code variable, which you obviously are not doing.
Add this mutator to your User model
public function setCodeAttribute($value)
{
$this->attributes['code'] = "Qwedf";
}
Anytime you are saving a record code will be assigned the Qwedf value