Query builder don't accept onlyTrashed() - mysql

I'm a beginner and cant find a solution to my problem. I trying to get "onlyTrashed" from my DB but Laravel 8 don't accept my query commands :( I tried many scenarios but unsuccessful.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use App\Models\Category;
class CategoryController extends Controller{
public function AllCat(){
$categories = $trashCat = DB::table('categories')
->join('users','categories.user_id','users.id')
->select('categories.*','users.name')
->latest()
->paginate(5);
//$categories = Category::latest()->paginate(5);
// $trashCat = Category::onlyTrashed()->latest()->paginate(3);
return view('admin.category.index', compact('trashCat','categories'));
public function SoftDelete($id){
$delete = Category::find($id);`enter code here`
return Redirect()->back()->wiht('success',' Category Delete Successfuly');
Route::get('/softdelete/category/{id}', [CategoryController::class,'SoftDelete']);

Please make sure that your model imports and uses SoftDeletes trait to implement soft delete in your model and make sure that your table has deleted_at field, your model may look like below codes.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
class Category extends Model
{
use SoftDeletes;
And in your SoftDelete function within the controller, I think you miss delete() function, your function should look like:
public function SoftDelete($id) {
$delete = Category::find($id)->delete();
return redirect()->back()->with('success',' Category Delete Successfully');
}
Once you implement SoftDeletes trait into your model, delete() function should mark deleted by filling the deleted_at with timestamp or DateTime automatically. Once you implement the above codes, onlyTrashed() should work.
$categories = Category::latest()->paginate(5);
$trashCat = Category::onlyTrashed()->latest()->paginate(3);

Related

Symfony 4 - update JSON user roles

I have entity User with field roles:
/**
* #ORM\Column(name="roles", type="json")
*/
private $roles = [];
public function getRoles(): array
{
return $roles = $this->roles;
}
public function setRoles($roles): self
{
$this->roles[] = $roles;
return $this;
}
I want to add functionality to update user role from ROLE_ADMIN to ROLE_USER. I tried this in my controller but instead of replacing ROLE_ADMIN with ROLE_USER it inerts this: "ROLE_ADMIN""ROLE_USER". This is my controller:
public function updateuser(Request $request, $id) {
$entityManager = $this->getDoctrine()->getManager();
$usr = $this->getDoctrine()->getRepository(User::class)->find($id);
$usr->setRoles("ROLE_USER");
$entityManager->persist($usr);
$entityManager->flush();
First of all its best practice that every users has at least a default role like ROLE_USER. If you want to give users extra roles then you add them with beside ROLE_USER, like for example ROLE_ADMIN.
Now take a close look how arrays work in PHP. Let's take the code of you setter function setRoles.
When you write the value assignment like this $this->roles[] = $roles, then a value is added to the array . Thats why you in you code you have both roles inside you array now. The already existing ROLE_ADMIN and after the function call you added ROLE_USER.
When you write the value assignment like this $this->roles = $roles, then the whole array is overwritten with the new value.
Conclusion:
Thats how you code should look like if you want a simple solution:
public function setRoles(array $roles): self
{
$this->roles = $roles;
return $this;
}
Then you can call it like this:
$user->setRoles(['ROLE_USER']);
The setRoles function only accepts array.
So your code should change accordingly:
$usr->setRoles(["ROLE_USER"]);
Furthermore, if you want to store it as json, you can use json_encode:
$usr->setRoles(json_encode(["ROLE_USER"]));

Yii Query Builder: Parametr binding using where() method

I have this code in my controller:
class ArchController extends Controller
{
public function actionIndex(string $date, array $rubric_id )
{
$articles = Article::find()->where('published < :date', [':date' => $date])
->andWhere(['in', 'rubric', $rubric_id])
->andWhere('ISNULL(arch)')->all();
...
It seems to me it is not safe because $rubric_id is user input. How can I make parametr binding, something like this:
':rubric_id' => $rubric_id
Yii uses parameter binding internally, so it is safe to use ->andWhere(['in', 'rubric', $rubric_id]). You can review implementation of InConditionBuilder to make sure of that.

Sort the parent model based on the child model / relationship

I have a model called appointments, each appointment has an option_id that is linked through a one to one relationship and the option_id can also be null. The option model has a property datetime_start. I want to sort the appointments based on the option.datetime_start.
Here is my code :
$appointments = $user->appointments()
->with(['option'
])
->get();
Edit :
Appointment model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Appointment extends Model
{
/**
* #return \Illuminate\Database\Eloquent\Relations\HasOne
*/
public function option()
{
return $this->hasOne(Option::class, 'id', 'option_id');
}
}
Option model :
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Option extends Model
{
protected $fillable = ["appointment_id",
"datetime_start"
];
public function appointment()
{
return $this->belongsTo(Appointment::class, 'id','appointment_id');
}
}
Any help would be greatly appreciated.
In order to sort Appointment model by a column from related Option model, you need to add a JOIN to your query so that you can sort by related fields:
$appointments = $user->appointments()
->leftJoin('options', 'options.appointment_id', '=', 'appointments.id')
->orderBy('options.datetime_start', 'ASC')
->with(['option'])
->get();
This will give you all appointments, including those without Option - the ones without an Option and, hence, without datetime_start, will be all returned either at the beginning or the end of the result list, you'll need to check that. If you only want appointments with Option, replace leftJoin() with join().
$appointments = Appointment::with(['option' => function ($query){ $query->orderBy('datetime_start', 'desc'); } ])->get();

Disable timestamps in Laravel model

I have simple model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class UserExt extends Model
{
protected $table = 'users_ext';
public $timestamps = false;
}
In controller i try to display some data from users_ext in controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use Illuminate\Support\Facades\Auth;
use App\UserExt;
class RegisterController extends Controller
{
public function registerCheck(Request $request){
$user_ext=UserExt::latest()->get();
return response()->json(array(
'users'=>$user_ext,
));
}
}
But i got an error with:
Column not found: 1054 Unknown column 'created_at' in 'order clause' (SQL: select * from users_ext order by created_at desc)
I thought, $timestamps=false will disable managing timestamp by Eloquent.
Do i have to do something else?
Would you mind showing your scopeLatest method in your model? I think the problem lie there, probably orderBy set to created at.

Yii2 - replacement for beforeFind to optimize nested views in MySql

Yii1 used to have beforeFind method in which you could modify the query or whatever else you might want to do.
In Yii2 the suggested alternative is to use the modelQuery solution for example
class MyModel extends \yii\db\ActiveRecord
{
public static function find()
{
return new MyModelQuery(get_called_class());
}
/* ... */
}
and
class MyModelQuery extends \yii\db\ActiveQuery
{
public function init( )
{
/** do something here **/
}
}
But how do I pass or reference MyModel within MyModelQuery?
For example:-
class MyModelQuery extends \yii\db\ActiveQuery
{
public function init( )
{
$sql = "SET #variable = {$MyModel->variable1}";
}
}
EDIT
For completeness, I've added a use case to help others in future.
I have nested views with group by's running under MySql and it runs VERY badly.
In my case, I have orders, order-items and order-item-fees tables, each one-to-many to the next and I want to sum the order totals. I have nested view, one at each level to sum to the level above, but at the order-item and order-item-fee levels MySql is grouping the whole table first (I cannot use algorithm=merge as I have a GROUP BY).
I'm implementing the Pushdown method where you define a SQL variable to use in sub-views to narrow down the search as outlined here: http://code.openark.org/blog/mysql/views-better-performance-with-condition-pushdown
and also here
https://www.percona.com/blog/2010/05/19/a-workaround-for-the-performance-problems-of-temptable-views/
In this way, if I can add a 'WHERE order_id=' to the where clause of the two sub-views, I reduce a 3.5 second query down to 0.003 second query.
So using, Salem's suggestion below, I can execute a SQL statement 'SET #order_id=1234' before my query, which is then picked up in the order-item and order-item-fee views using a function. Note: this is connection specific, so no danger of collisions between sessions.
A bit convoluted but fast.
It would be interesting, though, to see a performance comparison between SQL and looping in PHP perhaps....
EDIT 2
In fact, you normally use find() as a static method, so there is no way of using $this->order_id, so I changed this to over-ride the findOne method
public static function findOne( $orderId )
{
if ( isset($orderId) )
{
$sql = "SET #orderId='{$orderId}'";
Yii::$app->db->createCommand($sql)->execute();
}
return parent::findOne( $orderId );
}
I also use this view with other searches, so in the view I need to check whether the orderId is set or not ...
where (
CASE
WHEN ( NOT isnull( get_session_orderId() ) )
THEN `order`.order_id = get_session_cartref()
ELSE `order`.order_id LIKE '%'
END
)
About how to involve an ActiveQuery class check my answer here:
Yii2 : ActiveQuery Example and what is the reason to generate ActiveQuery class separately in Gii?
But if what you are trying to do doesn't require building named scopes then you may simply override the find method by something like this:
public static function find()
{
return parent::find()->where(['variable' => 'some value']);
}