Laravel firstOrCreate not merging the search entry - php

There's plenty of other questions surrounding this where people were using it wrong, but I'm confident I have the proper syntax and it's just leaving out the search term by the time it makes it to sql.
I've done 2 iterations. One where I add the 'sub' again and one where I don't
protected function upsertUser( $profile ) {
$sub = $profile['sub'];
$email = $profile['email'];
$name = $profile['name'];
Log::stack(['single'])->critical(compact("sub", "email", "name"));
return User::firstOrCreate(compact("sub"), ['sub' => $profile['sub'], 'email' => $profile['email'] ?? '', 'name' => $profile['name'] ?? '']);
}
protected function upsertUser( $profile ) {
$sub = $profile['sub'];
$email = $profile['email'];
$name = $profile['name'];
Log::stack(['single'])->critical(compact("sub", "email", "name"));
return User::firstOrCreate(compact("sub"), ['email' => $profile['email'] ?? '', 'name' => $profile['name'] ?? '']);
}
In both cases, sub just doesn't make it to the creation failing with:
A message showing that it doesn't even try to insert 'sub'
Logging the array shows that it contains the desired data.
Now I had come across a post where someone suggested that it was mass assignment protection stopping me from adding sub. I don't think it's related, but I tried to add
protected $fillable = [
'name',
'email',
'sub',
];
To the users model but it did not help. I do not want to allow nullable, because I need that data.

So this was terrible. I'm following along with this Auth0 sample app guide and in this sample they have a users model. I think this is default to laravel.
App/models/users != App/user
I had to make sub fillable on that "model" it's not even a traditional model it extends Auth\User

Related

How to get insert id after save to database in CodeIgniter 4

I'm using Codeigniter 4.
And inserting new data like this,
$data = [
'username' => 'darth',
'email' => 'd.vader#theempire.com'
];
$userModel->save($data);
Which is mentioned here: CodeIgniter’s Model reference
It's doing the insertion.
But I haven't found any reference about to get the inserted id after insertion.
Please help! Thanks in advance.
This also works.
$user= new UserModel();
$data = [
'username' => 'darth',
'email' => 'd.vader#theempire.com'
];
$user->insert($data);
$user_id = $user->getInsertID();
I got a simple solution after researching on the core of the CI 4 framework.
$db = db_connect('default');
$builder = $db->table('myTable');
$data = [
'username' => 'darth',
'email' => 'd.vader#theempire.com'
];
$builder->insert($data);
echo $db->insertID();
Hope they'll add a clear description on the docs soon.
There are three way to get the ID in ci4:
$db = \Config\Database::connect();
$workModel = model('App\Models\WorkModel', true, $db);
$id = $workModel->insert($data);
echo $id;
echo '<br/>';
echo $workModel->insertID();
echo '<br/>';
echo $db->insertID();
In fact, what you did is correct.
You did it in the best and easiest way and following the Codeigniter 4 Model usage guide.
You just missed: $id = $userModel->insertID;
Complete code using your example:
$data = [
'username' => 'darth',
'email' => 'd.vader#theempire.com'
];
$userModel->save($data);
$id = $userModel->insertID;
That's it. You don't need all this code from the examples above nor calling database service or db builder if you're using codeigniter's models.
Tested on CodeIgniter 4.1.1 on 3/19/2021
To overcome this, I modified system/Model.php in the save() method---
$response = $this->insert($data, false);
// add after the insert() call
$this->primaryKey = $this->db->insertID();
Now, in your models, you can just reference "$this->primaryKey" and it will give you the needed info, while maintaining the data modeling functionality.
I'm going to submit this over to the CI developers, hopefully it will be added in.
For CI4
$settings = new SettingsModel();
$settingsData = $settings->find(1);
<?php namespace App\Models;
use App\Models\BaseModel;
class SettingsModel extends BaseModel
{
protected $table = 'users';
protected $primaryKey = 'id';
}
$settings->find(1); will return a single row. it will find the value provided as the $primaryKey.
hi guys in my case i use ci model to save data and my code is :
$x=new X();
$is_insert= $x->save(['name'=>'test','type'=>'ss']);
if($is_insert)
$inserted_id=$x->getInsertID()
I'm using mysql for my database then I ran this inside my seeder
$university = $this->db->table('universities')->insert([
'name' => 'Harvard University'
]);
$faculty = $this->db->table('faculties')->insert([
'name' => 'Arts & Sciences',
'university' => $university->resultID
]);
Look at code line 6
$university->resultID
variable $university here is type object of CodeIgniter\Database\MySQLi\Result class
Corect me if I'm wrong or any room for improvements
I had the same problem but, unfortunately, the CI4 documentation doesn't help much. The solution using a builder woks, but it's a workaround the data modeling. I believe you want a pure model solution, otherwise you wouldn't be asking.
$data = [
'username' => 'darth',
'email' => 'd.vader#theempire.com'
];
$id = $userModel->save($data);
Trying everything I could think of I decided to store the result of the save method to see if returned a boolean value to indicate if the saving was sucessful. Inspecting the variable I realized it returns exactly what I wanted: the lost insertID.
I believe CodeIgniter 4 is quite an easy and capable framework that does a decent job in shared hosts where other frameworks can be a little demanding if you're learning but lacks the same fantastic documentation and examples of CI3. Hopefully, that's only temporary.
By the way, you code works only if you are using the $userModel outside the model itself, for example, from a Controller. You need to create a model object like:
$userModel = New WhateverNameModel();
$data = [any data];
$userModel->save($data);
Alternatively, if you are programming a method inside the model itself (my favorite way), you should write
$this->save($data);

Send a notification to user in Laravel 5.5

This is the scenario. I've User A that send via notification to other User B,C,D... a request to join a group. So in laravel I've created the migration and the controller to handle the notification.
This is the code of GroupController
...
foreach ($userINList as $userIN) {
$userIN = str_replace(' ', '', $userIN);
$userDBList = User::all();
foreach ($userDBList as $userDB) {
$name = $userDB->last_name . $userDB->first_name;
$name = str_replace(' ', '', $name);
if (strcmp($name, $userIN) == 0) {
$newGroup->users()->attach($userDB->id, ['role' => 'member', 'state' => 'pending']);
$notification = User::find($userIN->id);
$notification->notify(new GroupNotification($newGroup));
}
}
}
...
So in $notification I'll try to pass the id of Users that receive the invite and then I use the notify() method to send the notification, but after User A created the group and there aren't notifications to User B, C, D...
I've included the use Notifiable in group model. So what's the problem? What I've have to do.
Thanks
As far as I can tell from the code you're doing the following:
There is an array of names in the $userINList variable
You loop through each of the names in the array
Remove all spaces in the name
Retrieve every User
Loop through each User
Remove all the spaces in the User's name
Compare the 2 names
If the comparison passes then you add the User to the group and send a notification
There are quite a few improvements we can make here. For example, we already know which users you wish to notify so you do not need to fetch and compare all users.
Firstly, $userINList should either be an array of User objects or an array of User ids — an array of User objects is better. Then you can simply iterate through each one.
For example, if you have an array of ids then you could do this:
$group = Group::find(1);
$userINList = [1, 2, 3, 4];
User::whereIn('id', $userINList)
->get()
->each(function ($user) use ($group) {
$group->users()->attach($user->id, [
'role' => 'member',
'state' => 'pending'
]);
$user->notify(new GroupNotification($group));
});
And if you had an array of objects it would be even easier, you could do this:
$group = Group::find(1);
collect($users)->each(function ($user) use ($group) {
$group->users()->attach($user->id, [
'role' => 'member',
'state' => 'pending'
]);
$user->notify(new GroupNotification($group));
});
Super simple :-)

Not getting the id in where clause - Laravel 5.2

I need to get the record with special id and i have this in my method :
public function addedMark()
{
$user = Auth::user();
$subject = ClassSubject::where('teacher_id', $user->id)->pluck('id','subject_id');
return view('educator.account.marks', [
'user' => $user,
'marks' => StudentMark::where('subject_id', $subject)->get()
]);
}
When i do dd(ClassSubject::where('teacher_id', $user->id)->pluck('id','subject_id')); i see that I'm getting the information that i need, but when i do dd(StudentMark::where('subject_id', $subject)->get()); it returns an empty array.
Any idea why?
Change it to (whereIn)
'marks' => StudentMark::whereIn('subject_id', $subject)->get()
and let see what hapens
In $subjectyou have id and subject_id. You might wanna just take subject_id.
So change this: StudentMark::where('subject_id', $subject)->get()
to
StudentMark::where('subject_id', $subject[1])->get()

Laravel - Saving data to many-to-many relationship

is it possible to save more data than just the id's to a many-to-many pivot?
My Code:
public function lists() {
return $this->belongsToMany('ShoppingList','shopping_list_ingredients','shopping_list_id','ingredients_id')
->withPivot(array('unit','amount'))
->withTimestamps();
}
and vice verca!
And now, I need to add the additional data to the pivot.
This is my saving code:
$list = new ShoppingList;
$list->user_id = Auth::user()->id;
$list->title = Input::get('recipe_title');
$list->save();
$list->ingredients()->sync(Input::get('ingredient'));
$list->push();
and my view code:
- {{$i->amount}} {{$i->unit}} {{$i->name}} - {{ Form::checkbox('ingredient[]', $i->id) }}<br/>
Now I need somehow pass the "amount" and "unit" for each ID into the controller and into the pivot. Right now, it only saves the IDs.
How can I do it?
You have to use the attach function.
$list->ingredients()->attach($ingredients->id,['unit' => $unit, 'amount' => $amount]);
You may try something like this:
$ingredientId = Input::get('ingredient');
$amount = 'some amount';
$unit = 'some unit';
$pivotData = array($ingredientId => array('amount' => $amount, 'unit' => $unit));
$list->ingredients()->sync($pivotData);
You may also use attach method, read the documentation on Laravel Website for more information.

Using the CakeDC search plugin with associated models

I'm using CakePHP 1.3.8, and I've installed the CakeDC Search plugin. I have a Tutorial model, which is in a HABTM relationship with a LearningGoal model.
I have a search action & view in the Tutorials controller with which I can successfully search fields in the Tutorial model. I'd also like to filter my tutorial search results using LearningGoal checkboxes on the same form. I've tried adding various parameters to Tutorial's $filterArgs and TutorialsController's $presetVars. I've also tried moving the relevant $filterArgs to the LearningGoal model. I have not yet been able to successfully trigger the entry for learning goals in $filterArgs.
I think I must be missing something obvious. Or maybe the Search plugin doesn't support what I'm trying to do. Does anyone know how to use this plugin to search on associated models?
So here's what I've figured out. You can combine what's below with the Search plugin directions to search on related models.
The $filterArgs piece in the Tutorial model must look like this:
var $filterArgs = array(
array('name' => 'LearningGoal', 'type' => 'subquery', 'method' => 'findByLearningGoals', 'field' => 'Tutorial.id'),
);
Here's the supporting function in the Tutorial model:
function findByLearningGoals($data = array()) {
$ids = explode('|', $data['LearningGoal']);
$ids = join(',', $ids);
$this->LearningGoalsTutorial->Behaviors->attach('Containable', array('autoFields' => false));
$this->LearningGoalsTutorial->Behaviors->attach('Search.Searchable');
$query = $this->LearningGoalsTutorial->getQuery('all',
array(
'conditions' => array('LearningGoalsTutorial.learning_goal_id IN (' . $ids . ')'),
'fields' => array('tutorial_id'),
)
);
return $query;
}
In TutorialsController, $presetVars should look like this:
public $presetVars = array(
array('field' => 'LearningGoal', 'type' => 'checkbox', 'model' => 'Tutorial'),
);
And in my search action in TutorialsController, I did this:
$this->LearningGoal = $this->Tutorial->LearningGoal;
The Prg component seems to need that.
I am using CakePHP version 2.X
Every time I come to do this in a project I always spend hours figuring out how to do it using CakeDC search behavior so I wrote this to try and remind myself with simple language what I need to do. I've also noticed that although Michael is generally correct there is no explanation which makes it more difficult to modify it to one's own project.
When you have a "has and belongs to many" relationship and you are wanting to search the joining table i.e. the table that has the two fields in it that joins the tables on either side of it together in a many-to-many relationship you want to create a subquery with a list of IDs from one of the tables in the relationship. The IDs from the table on the other side of the relationship are going to be checked to see if they are in that record and if they are then the record in the main table is going to be selected.
In this following example
SELECT Handover.id, Handover.title, Handover.description
FROM handovers AS Handover
WHERE Handover.id in
(SELECT ArosHandover.handover_id
FROM aros_handovers AS ArosHandover
WHERE ArosHandover.aro_id IN (3) AND ArosHandover.deleted != '1')
LIMIT 20
all the records from ArosHandover will be selected if they have an aro_id of 3 then the Handover.id is used to decide which Handover records to select.
On to how to do this with the CakeDC search behaviour.
Firstly, place the field into the search form:
echo $this->Form->create('Handover', array('class' => 'form-horizontal'));?>
echo $this->Form->input('aro_id', array('options' => $roles, 'multiple' => true, 'label' => __('For', true), 'div' => false, true));
etc...
notice that I have not placed the form element in the ArosHandover data space; another way of saying this is that when the form request is sent the field aro_id will be placed under the array called Handover.
In the model under the variable $filterArgs:
'aro_id' => array('name' => 'aro_id', 'type' => 'subquery', 'method' => 'findByAros', 'field' => 'Handover.id')
notice that the type is 'subquery' as I mentioned above you need to create a subquery in order to be able to find the appropriate records and by setting the type to subquery you are telling CakeDC to create a subquery snippet of SQL. The method is the function name that are going to write the code under. The field element is the name of the field which is going to appear in this part of the example query above
WHERE Handover.id in
Then you write the function that will return the subquery:
function findByAros($data = array())
{
$ids = ''; //you need to make a comma separated list of the aro_ids that are going to be checked
foreach($data['aro_id'] as $k => $v)
{
$ids .= $v . ', ';
}
if($ids != '')
{
$ids = rtrim($ids, ', ');
}
//you only need to have these two lines in if you have not already attached the behaviours in the ArosHandover model file
$this->ArosHandover->Behaviors->attach('Containable', array('autoFields' => false));
$this->ArosHandover->Behaviors->attach('Search.Searchable');
$query = $this->ArosHandover->getQuery('all',
array(
'conditions' => array('ArosHandover.aro_id IN (' . $ids . ')'),
'fields' => array('handover_id'), //the other field that you need to check against, it's the other side of the many-to-many relationship
'contain' => false //place this in if you just want to have the ArosHandover table data included
)
);
return $query;
}
In the Handovers controller:
public $components = array('Search.Prg', 'Paginator'); //you can also place this into AppController
public $presetVars = true; //using $filterArgs in the model configuration
public $paginate = array(); //declare this so that you can change it
// this is the snippet of the search form processing
public function admin_find()
{
$this->set('title_for_layout','Find handovers');
$this->Prg->commonProcess();
if(isset($this->passedArgs) && !empty($this->passedArgs))
{//the following line passes the conditions into the Paginator component
$this->Paginator->settings = array('conditions' => $this->Handover->parseCriteria($this->passedArgs));
$handovers = $this->Paginator->paginate(); // this gets the data
$this->set('handovers', $handovers); // this passes it to the template
If you want any further explanation as to why I have done something, ask and if I get an email to tell me that you have asked I will give an answer if I am able to.

Categories