I tried to accomplish a multiple where clause but failed. I want to check if the current Date of the user is equal to created_at and the second clause would be if the user has an entry by user id. I am working on a fitness app where the User can track the km he has run. And rather to create in a database table new entries just add them to the existing entries.
My Question is focused on the problem with the if clause because the variable $hasUserEntries is not equal to null but there is no entry in the database table. It is empty.
I tried instead of using get() I used first(). But the problem is that I wasn't able to use Carbon::today() or it was maybe that I use 3 values in the where clause which I need because I can't get the created_at date only the Date YYYY-MM-DD. At the first() Statement I used a hardcoded DateTime to check with created_at and it worked. But I think I must not explain why hardcode is not optimal.
I searched on Stackoverflow and find that most answers were about using get(). It is fine but why does my else get triggered because from my point of view the database is empty(Null) so the if($hasUserEntries==null)should be triggered.
public function add_km_to_progressbar(Request $request, TrackKM $trackKM)
{
$track_dailies = new TrackDaily();
$track_dailies->user_id = \Auth::user()->id;
$amount_runned_km = $request->input('amount_runned_km');
$amount_runned_km = (int)$amount_runned_km;
$track_dailies->amount = (int)$amount_runned_km;
$track_dailies->type = 1;
$check_requirements = [
'user_id'=>\Auth::user()->id,
'created_at'=>'Carbon::today()'
];
$hasUserEntries = DB::table('track_dailies')
->where('user_id','=',\Auth::user())
->where('created_at','>=',Carbon::today())
->get();
if ($hasUserEntries == null) {
return dd('does not work');
} else {
return dd('does work');
}
}
Expected Result should be the triggering of the if statement because if the database table is empty, the user id does not exist or the date of created_at is not the same as the current date then should be triggered if($hasUserEntries==null). I want to create there a new row if this condition == null in the database.
Actual Result if($hasUserEntries==null) is true even though that the database table is empty. I think that the method get() has values saved that are not related to the database.
I hope that you can help me out.
i think what you should have done is checking to see if the record exist in the database before proceeding...
$checkifuserExist= DB::table('track_dailies')->where('user_id','=',\Auth::user())->where('created_at','>=',Carbon::today())->count();
if($checkifuserExist>0)
{
//proceed to query for fitness
}
else
{
//do something else...
}
with this, it will not throw error!
Try this if case intead:
if (is_empty($hasUserEntries))
$checkifuserExist= DB::table('track_dailies')->where('user_id','=',\Auth::user())->where('created_at','>=',Carbon::today())->count();
if($checkifuserExist>0)
{
//if user really exists
if( $hasUserEntries = DB::table('track_dailies')->where('user_id','=',\Auth::user())->where('created_at','>=',Carbon::today())->first())
{
//update the value of the amount
}
else{
//insert new record
}
}
else
{
// if the user does not exist, do something else...
}
remember theres no way the record for user_id would be null because first there has to be record inside the db
Related
I wanted to let the system to show error message when detect duplicated entry of full_name column without applying unique in the full_name column from public function rules() in model.
My code is like this :
if ($model->load(Yii::$app->request->post()) ) {
$model->full_name = $model->first_name .'' . $model->last_name ;
$name = StudentInfo::find()->select('full_name')->where(['full_name'=> $model->full_name]);
if($name == $model->full_name ){
echo "<script type='text/javascript'>alert('Same student name is detected');</script>";
}
else{
$model->status ="Active";
$model->call_format = Countries::find()->select('phonecode')->where(['name'=> $model->country]);
$model->date_created = new Expression('NOW()');
$user->user_type ='student';
$user->user_name = $model->full_name;
$user->user_status = $model->status;
$user->authKey = Yii::$app->security->generateRandomString(10);
$user->accessToken = Yii::$app->security->generateRandomString(10);
$user->save();
$model->save();
return $this->redirect(['view', 'id' => $model->id]);
}
}
But it shows error like :missing required parameters: id. When i apply model->save(false) ,it seems that the sql statement wont run because of duplicate entry in full_name column. How do i fix it?
Well, there is a construct exists() for such a purposes (see Yii2: check exist ActiveRecord model in database ).
if(StudentInfo::find()->where(['full_name'=> $model->full_name])->exists()){
echo "<script type='text/javascript'>alert('Same student name is detected');</script>";
}
else{...}
it generates the EXISTS query, which is faster and you don't have to load all the data from DB.
If you don't have such a column in your table, then check it by the first/last name.
change it:
$name = StudentInfo::find()->select('full_name')->where(['full_name'=> $model->full_name]);
To:
$name = StudentInfo::find()->select('full_name')->where(['full_name'=> $model->full_name])->one();
Also, if you use the select() method, to use the update() and save() or updateCounters() ... methods, you need the row ID in the same query.
Example:
->select('id') or ->select(['id', 'full_name'])
info: Multi-parameter is an array in select()
:missing required parameters: id
could mean that it couldn't find id, not by duplicate entry in full_name column. please check again
There are two problems with your code.
$name = StudentInfo::find()->select('full_name')->where(['full_name'=> $model->full_name]);
When this line is executed the $name variable will contain instance of yii\db\ActiveQuery. You want to call some method, that will actually execute your query and return result.
You can use scalar() to get the selected value. In that case the $name will contain the content of full_name column from result.
$name = StudentInfo::find()
->select('full_name')
->where(['full_name'=> $model->full_name])
->scalar();
Or you can use count() to get the number of rows that match condition. In that case you may leave out the select() method call but you will need to modify your condition
$count = StudentInfo::find()
->where(['full_name'=> $model->full_name])
->count();
if ($count > 0) {
echo "<script type='text/javascript'>alert('Same student name is detected');</script>";
} else {
// ...
}
The other problem is that you are not checking whether your $model->save() was successful. If your $model is new instance and the id attribute is auto-generated then when $model->save fails the $model->id is empty and then you are trying to redirect user to view with empty id.
Your code should look like this:
if ($user->save() && $model->save()) {
return $this->redirect(['view', 'id' => $model->id]);
}
If the save fails because of validation the validation errors will be stored in models and if you are using ActiveForm widget the errors will be displayed. If you are not using ActiveForm you should do something to tell user that operation failed.
Since you are saving two different models you might want to consider use of transactions to prevent a situations where $user model is saved but save of $model fails.
I need to increment 'total_products' field in Categories table every time a new product is added. But I don't want it to increase when an existing product is UPDATED. I'm doing this right now:
Category::findOrNew($product->cat_id)->increment('total_products',1);
But this code doesn't recognize whether its an update or a new insert. It increases 'total_products' no matter its an insert or update. How can I make it increment only when its a new insert?
It is clearly two query, try each with separate query
$cat = Category::find($product->cat_id);
if($cat){
$cat->increment('total_products',1);
}else{
$cat = new Category();
$cat->total_products = 1;
// Inert new category here with all related data
$cat->save();
}
return $cat->id;
Also be sure about when to increase total_products ? after insert or after update.
Use the firstOrCreate method for that:
$category = Category::firstOrCreate(['name' => 'John Doe']);
If you want to know whether the user was created or fetched, check the wasRecentlyCreated property:
if ($category->wasRecentlyCreated) {
// "firstOrCreate" didn't find the user in the DB, so it created it.
} else {
// "firstOrCreate" found the user in the DB and fetched it.
}
You can set total_products field to 0 by default in the migration:
$table->integer('total_products')->default(0);
Then findOrCreate and increment:
Category::query()
->findOrCreate($product->cat_id)
->increment('total_products');
I have 2 models Tour.php
public function Itinerary()
{
return $this->hasMany('App\Itinerary', 'tour_id');
}
and
Itinerary.php
public function tour()
{
return $this->belongsTo('App\Tour', 'tour_id');
}
tours table:
id|title|content
itineraries table:
id|tour_id|day|itinerary
I have used vue js to create or add and remove input field for day and plan dynamically. And used the following code in tour.store method to insert into itineraries table:
$count = count($request->input('day'));
$temp_day = $request->input('day');
$temp_itinerary = $request->input('itinerary');
for($i = 0; $i < $count; ++$i)
{
$itinerary = new Itinerary;
$itinerary->tour_id = $tour->id;
$itinerary->plan = $temp_itinerary[$i];
$itinerary->day = $temp_day[$i];
$itinerary->save();
}
And was successful in inserting the records.And applied same code in tour.store method. Instead of updating the rows, it inserted new rows to the table. What would be the best solution for this ?
For updation try this code
$itinerary = Itinerary::find($tour_id);
$itinerary->plan = $temp_itinerary[$i];
$itinerary->day = $temp_day[$i];
$itinerary->save();
The way you are using is to insert/create new records. To update you can use.
Itinerary::find($tour_id)->update(
['column_name'=> value]
);
Where find method takes a primary key of the table.
This will update your existing record. You can update as many columns as you want just pass in array update takes. You can also use save method as mentioned in other answer.
Check Laravel Update Eloquent
EDIT
$iterneary = Itenerary::where('tour_id', $tour_id)->first();
Now you can update this iterneary object to whatever you want.
this is how i did it. First saved all the tours in $tours[] array.
foreach($tours as $tour) {
$itinerary->tour()->updateOrCreate(['id'=> $tour['id']],$tour);
}
updateOrCreate because you may need to add new tours while updating. I know this doesnt answer your issue exactly but this could atleast give you an idea.
I've set up a log in process where a verification code is generated, and when successful, is then removed. However, i want to make sure that if there's multiple verification codes for the same user, upon log in success, delete all records for that user.
Here's my code
if ($model->validate() && $model->login()) {
//delete this verification code
$verificationCode->delete();
//delete all existing codes for user_id
VerificationCode::model()->deleteAll('user_id',$user->id);
Yii::app()->user->setReturnUrl(array('/system/admin/'));
$this->redirect(Yii::app()->user->returnUrl);
}
However, this seems to just delete all the records, regardless on different user_id's in table. Can anyone see where I'm going wrong?
If you want to delete record with specified attributes, the cleanest way for this is to use deleteAllByAttributes():
VerificationCode::model()->deleteAllByAttributes(['user_id' => $user->id]);
Seems you call the function delete() in wrong way ... try passing value this way
VerificationCode::model()->deleteAll('user_id = :user_id', array(':user_id' => $user->id));
For Yii2, the documented way is to use the function deleteAll().
I normally pass the arguments as an array, like so:
VerificationCode::deleteAll(['user_id' => $user->id]);
Also, you can use the afterDelete method, to make sure that everytime or everywhere someone deletes one verificationCode, your application will also delete every userVerificationCode. Put this in your verificationCode model class:
protected function afterDelete()
{
parent::afterDelete();
VerificationCode::model()->deleteAll('user_id = :user:id',[':user_id' =>$this->user_id]);
//... any other logic here
}
You can use below method for deleting all user_id entry from database:
$criteria = new CDbCriteria;
// secure way for add a new condition
$criteria->condition = "user_id = :user_id ";
$criteria->params[":user_id"] = $user->id;
// remove user related all entry from database
$model = VerificationCode::model()->deleteAll($criteria);
or you can use another method directly in controller action
VerificationCode::model()->deleteAll("user_id= :user_id", [":user_id"
=>$user->id]);
use below method for redirecting a URL
$this->c()->redirect(Yii::app()->createUrl('/system/admin/'));
I have two models, Position and User. They have a One to many relation between them.
When I delete a position, I want all the related users to be detached from that position and attached to a different one (found by id).
I'm sure it's simple enough, but I've tried doing it in a foreach loop, without success:
public function postDelete($position)
{
$positionMembers = $position->users()->get();
foreach ($positionMembers as $member) {
$member->position_id = '4';
// fixed copy/paste var name error
$member->save()
}
// Was the position deleted?
if($position->delete()) {
// Redirect to the position management page
return Redirect::to('admin/positions')->with('success', Lang::get('admin/positions/messages.delete.success'));
}
// There was a problem deleting the position
return Redirect::to('admin/positions')->with('error', Lang::get('admin/positions/messages.delete.error'));
}
I've also tried:
$member->position()->associate($this->position->find(4));
but it doesn't work either. The position_id field always remains unchanged. Is there a more recommended way?
First off define without success, because it says nothing, and the code you're showing should work.
Anyway, I would suggest different approach, for using Eloquent save in a loop isn't the best way:
public function postDelete($position)
{
DB::transaction(function () use ($position, &$deleted) {
// run single query for update
$position->users()->update(['position_id' => 4]);
// run another query for delete
$deleted = $position->delete();
});
// Was the position deleted?
if($deleted) {
// Redirect to the position management page
return Redirect::to('admin/positions')->with('success', Lang::get('admin/positions/messages.delete.success'));
}
// There was a problem deleting the position
return Redirect::to('admin/positions')->with('error', Lang::get('admin/positions/messages.delete.error'));
}
With this, you make sure users don't get updated if there's some error(exception thrown) when deleting position and you execute 2 queries, no matter how many users there are to update.