build a query with conditional where clause in eloquent model - mysql

I need to build a query with eloquent model including conditional where clause. I created something by searching google. But it doesn't seems to be working.
if ($status) {
$this->where('status', $status);
}
if ($assignedto) {
$this->where('assigned_to', $assignedto);
}
if ($fromDate != null && $toDate != null) {
$this->whereBetween('date', array($fromDate, $toDate));
}
$quotes = $this->orderBy('date', 'desc')->paginate(40);
This one returns all results without the filtering of status, assigned to and dates.

I just updated it by assigning $this to a new variable because when I assigned the query to $this, it shown an error, $this cannot be over written.
$quoteModel = $this;
if ($status) {
$quoteModel = $quoteModel->where('status', $status);
}
if ($assignedto) {
$quoteModel = $quoteModel->where('assigned_to', $assignedto);
}
if ($fromDate != null && $toDate != null) {
$quoteModel = $quoteModel->whereBetween('date', array($fromDate, $toDate));
}
$quotes = $quoteModel->orderBy('date', 'desc')->paginate(40);
which works perfectly now. But if somebody have some better option, please suggest. Thanks.

I added a scope to my model and call it from the controller. This way the actual filtering work is done in the model, the controller is just running the query through the filter scope.
Model:
I am getting URL parameters with Input::get, but you would also pass them as input parameters to the function.
public function scopeFilter($query)
{
$published = Input::get('published');
if (isset($published)) $query->where('published', '=', $published);
return $query;
}
Controller:
Here the query is run through the filter() before returning it to the view.
public function index()
{
return View::make('articles.index', [
'articles' => Article::with('writer')->filter()->get()
]);
}

Related

Using ST_Intersects ST_Overlaps ST_within and ST_Equals at the same time

Currently using Grimzy Laravel MySQL Spatial, but this is basically just converting it to proper SQL queries.
I need to search whether an area intersects or overlaps or within or equal or contains to the polygon stored in DB.
public function __construct($areaPerimeterCoordinates = null)
{
$this->area = Polygon::fromJson($areaPerimeterCoordinates);
}
public function handle()
{
//this is the first query - it is working and returning result
//need to refine it to check contains/same
//$query = Property::intersects('area_perimeter', $this->area);
//working on this query - this returns empty
$query = Property::where(function($qry) {
$qry->intersects('area_perimeter', $this->area);
})->orWhere(function($qry) {
$qry->overlaps('area_perimeter', $this->area);
})->orWhere(function($qry) {
$qry->within('area_perimeter', $this->area);
})->orWhere(function($qry) {
$qry->equals('area_one_perimeter', $this->area);
})->orWhere(function($qry) {
$qry->contains('area_perimeter', $this->area);
});
$properties = $query->get();
if(!$properties->isEmpty()) {
throw new PropertyExistsException(null, $properties);
}
}
Note: As per checking the first query and editing it to use groupings by adding a closure, it also returns empty. Weird?
$query = Property::where(function($qry) {
$qry->intersects('area_perimeter', $this->area);
});
$properties = $query->get();//empty
Additional note: Now this ST_intersect sometimes work and sometimes does not work...
Really appreciate any advice. Thank you.

Codeigniter how to return multiple rows from same column in model

I need to get all the rows which are filters by the query. But only the first row is returned from the model to the controller.
Given below is my model function. How to get all the data needed?
public function getOfferTags($param) {
$this->db->select('tags.*');
$this->db->from('tags');
$this->db->join('offer_tag', 'offer_tag.tag_id = tags.id');
$this->db->join('offers', 'offers.id = offer_tag.offer_id');
$this->db->where('offers.id', $param);
$query = $this->db->get();
return $query->row();
}
Simply not return row and on that place fetch as an array form like
return $query->result_array();
After that checks in controller and get the result in array.
I just wanted to add, because you are new to CI, that you should always check if their are rows before using the array to prevent notices or issues. with mehta's method you would do if(count($rows) > 0) { //rows exist } else { // no rows, display error .etc. } or you can do:
$query = $this->db->get();
if ($query->num_rows() > 0) {
return $query->result_array(); // or result() for obj
}
return false;
Usage:
if ($this->somemodel->getOfferTags($stmt)) {
// has data
} else {
// no data
}
It is important to start with good practices and this will help ;)

count(): Parameter must be an array or an object that implements Countable in php 7.2.1

count(): Parameter must be an array or an object that implements Countable in php 7.2.1
using Yii2
How to resolve this issue?
public static function findAdminByUsername($username)
{
$adminUser = static::find()->where(['username' => $username,'userType'=>'ADMIN','user_status'=>self::STATUS_ACTIVE])->one();
if(count($adminUser)>0){
return $adminUser;
}else{
return null;
}
}
The thing is you are checking for count > 1 with using ->one() which looks odd, looking at your code you want to return NULL if there is no record found and if you look into documentation the function one() already returns NULL if there are no records found so you are adding extra code and it could easily be reduced to
public static function findAdminByUsername($username)
{
return static::find()->where(
[
'username' => $username,
'userType' => 'ADMIN',
'user_status' => self::STATUS_ACTIVE,
]
)->one();
}
You are using find()......->one()
so your query should return just an object .. without iteration capabilities.
if you want check if the find() return a value or not then you could check with isset. find()->one() return null if the query fail.
public static function findAdminByUsername($username)
{
$adminUser = static::find()->where(['username' => $username,'userType'=>'ADMIN','user_status'=>self::STATUS_ACTIVE])->one();
if( $adminUser !== null ){
return $adminUser;
}else{
return null;
}
}
if you don't need others that return the result for find()->..one() you could simply return
return static::find()->
where(['username' => $username,'userType'=>'ADMIN','user_status'=>self::STATUS_ACTIVE])
->one();

Passing Laravel Collection to Vue

I am trying to return customers from model Customer where id < 10. I do have some in the database.
$customers = Customer::where('id', '<', 10)->get();
return json_encode(['customers' => $customers]);
The above code will error out "Trailing data"
and when I try to dd($customers), I get a list of the collection Customer
I have no idea why I keep getting that and why the model is returning raw collection and not an object of the list of customers???
It seems like a null date "updated_at" field is causing the error. don't know why!
Solved By:
on the Customer model I had to do:
//ask Laravel to not manage default date columns
public $timestamps = false;
also I to mutate those columns:
public function setDateRemindedAttribute($value)
{
if (strlen($value)) {
$this->attributes['date_reminded'] = Carbon::createFromFormat('d/m/Y', $value);
} else {
$this->attributes['date_reminded'] = null;
}
}
public function setUpdatedAtAttribute($value)
{
if (strlen($value)) {
$this->attributes['updated_at'] = Carbon::createFromFormat('d/m/Y', $value);
} else {
$this->attributes['updated_at'] = $_SERVER['REQUEST_TIME'];
}
}
Use response()->json() like this
$customers = Customer::where('id', '<', 10)->get();
return response()->json(['customers' => $customers]);

How to select all rows except (A and B) in Eloquent ORM using Scope?

I'm trying to figure out how to get all rows except few (A and B) in Eloquent ORM modal.
User Model
public function notifications()
{
return $this->hasMany('notification','listener_id','id');
}
Model Notification
public function scopeFriendship($query)
{
return $query->where('object_type', '=', 'Friendship Request');
}
public function scopeSent($query)
{
return $query->where('verb', '=', 'sent');
}
Here how can I get all notifications of a user except other than (Friendship and Sent) scope.
Something like:- all rows except !(Friendship AND Sent)
It is possible to use scopes in combination with eager loading. Like that:
User::with(['notifications' => function($q){
$q->friendship();
}])->get();
However we now need to invert the scope somehow. I can think of two ways to solve this.
1. Add negative scopes
public function scopeNotFriendship($query){
return $query->where('object_type', '!=', 'Friendship Request');
}
public function scopeNotSent($query){
return $query->where('verb', '!=', 'sent');
}
User::with(['notifications' => function($q){
$q->notFriendship();
$q->notSent();
}])->get();
2. Optional parameter
Or you could introduce an optional parameter to your current scopes. Something like this:
public function scopeFriendship($query, $is = true)
{
return $query->where('object_type', ($is ? '=' : '!='), 'Friendship Request');
}
public function scopeSent($query, $is = true)
{
return $query->where('verb', ($is ? '=' : '!='), 'sent');
}
This way you would only have to pass in false:
User::with(['notifications' => function($q){
$q->friendship(false);
$q->sent(false);
}])->get();
Edit
You can even gain more control by adding a second parameter for the boolean (AND or OR of the where:
public function scopeFriendship($query, $is = true, $boolean = 'and')
{
return $query->where('object_type', ($is ? '=' : '!='), 'Friendship Request', $boolean);
}
And if you wanted either scope to be true:
$q->friendship(true, 'or');
$q->sent(true, 'or');
2nd Edit
This one finally worked (from the chat)
Notification::where('listener_id', $user_id)
->where(function($q){
$q->friendship(false)
$q->sent(false, 'or')
})
->get();