I am applying search filter in my project so first of all I get data from multiple tables and store in two different variables and then merge these two variable into one so I can filter data from that merged variable. So my code is like that
$data1=Model::query()
->Join('...')
->leftJoin('...')
->where('id',login_user)
->select(...)
->whereRaw('id IN (select MAX(id) FROM table GROUP BY name)')
->groupBy('name')
->get();
$data2=Model2::query()
->leftJoin(...)
->select(...)
->where('id',login_user)
->whereNotIn(..)
->get();
both data1 and data2 return same column with different values so I merge both variable like that
$results = $data1->concat($data2);
No when I already get data so now I need to add filter data from $results so i make post method for that .
so When user request to filter data with name I write query like that
if ($request->name!="") {
$results->when(request('name'), function($q){
$q->Where('name', request('name'));
});
}
$records = $results;
return response()->json(['success'=>true,'message'=>'success', 'data' => $records]);
But that query is not filtering the data and return me all data.I am new in laravel so I don't know what I have done wrong in that any favour will be helpful for me ,thanks.
if (request()->has('name')) {
$results->when(request()->get('name'), function($q){
return $q->where('name', request()->get('name'));
});
}
$records = $results;
return response()->json(['success'=>true,'message'=>'success', 'data' => $records]);
As you use 'when()', you can drop the if expression all together:
$results->when(request()->has('name'), function($q){
return $q->where('name', request()->get('name'));
});
$records = $results;
return response()->json(['success'=>true,'message'=>'success', 'data' => $records]);
request() is a Laravel helper for Request $request
Edit: the where() clause in the ORM is with a small 'w', not 'W' as in orWhere
Related
So, i need to put AWS S3 URL before the attachment value. I use Laravel Query builder to get data from database.
Query
$query = DB::table('subscriber')->select(['ID as SBC_ID','SUBSCRIBER_NAME','ATTACHMENT_OTHERS'])
->get();
return $query;
Result
[
{
"SBC_ID": 1,
"SUBSCRIBER_NAME": "NAME",
"ATTACHMENT_OTHERS": "uploads/1655362922-Annotation%202022-05-31%20141139.png"
},
{
"SBC_ID": 2,
"SUBSCRIBER_NAME": "NAME 2",
"ATTACHMENT_OTHERS": "uploads/1655362922-image.png"
}
]
The ATTACHMENT_OTHERS is from Form Request and uploaded to AWS S3. I just insert the attachment path, not full S3 URL. But now, i need to return full URL.
Let say i put my AWS url in the .env file.
AWS_URL=https://loremipsum.s3.ap-southeast-1.amazonaws.com
Is it possible to return the result from my query builder ?
You can use Laravel Raw Expressions and MySQL CONCAT function. E.g.:
$query = DB::table('subscriber')
->select([
'ID as SBC_ID',
'SUBSCRIBER_NAME',
DB::raw('CONCAT(\'https://loremipsum.s3.ap-southeast-1.amazonaws.com\', ATTACHMENT_OTHERS) as ATTACHMENT_OTHERS')
])->get();
Additionally, you put that url in .env
AWS_URL=https://loremipsum.s3.ap-southeast-1.amazonaws.com
and create new config file, e.g. config/aws.php
return [
'attachment_url' => env('AWS_URL', 'AWS_URL'),
]
and then you can have a little neater code:
$query = DB::table('subscriber')
->select([
'ID as SBC_ID',
'SUBSCRIBER_NAME',
DB::raw('CONCAT(\''.config('aws.attachment_url').'\', ATTACHMENT_OTHERS) as ATTACHMENT_OTHERS')
])->get();
If you returning this data via JSON API, then I suggest that you use Laravel API Resources
You can use SQL's built-in function CONCAT() with DB facade, something like like this:
use Illuminate\Support\Facades\DB;
// ...
$aws_host = "https://loremipsum.s3.ap-southeast-1.amazonaws.com" . "/";
$query = DB::table('subscriber')->select([
'ID as SBC_ID',
'SUBSCRIBER_NAME',
DB::raw('CONCAT("' . $aws_host . '", ATTACHMENT_OTHERS) AS ATTACHMENT_OTHERS'),
])->get();
$query = DB::table('subscriber')->select(['ID as SBC_ID','SUBSCRIBER_NAME','ATTACHMENT_OTHERS'])
->get();
$AWS_URL = "https://loremipsum.s3.ap-southeast-1.amazonaws.com/";
foreach($query as $result)
{
$SBC_ID = $result->SBC_ID;
$SUBSCRIBER_NAME = $result->SUBSCRIBER_NAME;
$ATTACHMENT_OTHERS = $AWS_URL.$result->ATTACHMENT_OTHERS;
}
$query = ([
'SBC_ID' => $SBC_ID,
'SUBSCRIBER_NAME' => $SUBSCRIBER_NAME,
'ATTACHMENT_OTHERS' => $ATTACHMENT_OTHERS
]);
return $query;
I'm scratching my head over this database query and couldn't find out why it is not working.
It actually works if I try it directly on the plays table :
Play::select(\DB::raw('COUNT(*) as plays'), \DB::raw('DATE(created_at) as date'))
->whereDate('created_at', '>', Carbon::now()->subWeek())
->groupBy('date')->orderBy('date')->get();
// returns the expected results
However, it does not work when I try to use it inside relation function ( returns empty array, while there is actually data ):
$artist->songs()->with(['plays' => function($q){
$q->select(\DB::raw('COUNT(*) as plays'), \DB::raw('DATE(created_at) as date'))
->whereDate('created_at', '>', Carbon::now()->subWeek())
->groupBy('date')->orderBy('date');
}])->get()->pluck('plays')->toArray();
NB: $artist->songs()->with('plays')->get() return the expected results
I guess you need to send id inside select statement.
$artist->songs()->with(['plays' => function($q){
$q->select(\DB::raw('COUNT(*) as plays'), \DB::raw('DATE(created_at) as date'), 'id')
->whereDate('created_at', '>', Carbon::now()->subWeek())
->groupBy('date')->orderBy('date');
}])->get()->pluck('plays')->toArray();
I'm still new to this laravel, for now I'm facing a trouble for fetching data from the database. What i want to get is when there are only one data available, the second parameters won't be executed, but if there are some data available on the second parameters, then all the data from first parameter and the second parameter will be called.
$detail = Barang_Keluar_Detail::findOrFail($id); //15
$cariid = $detail->pluck('barang_keluar_id');
$instansiquery = Barang_Keluar::where('id',$cariid)->first(); //21
$instansiid = $instansiquery->pluck('instansi_id');
$tanggal = $instansiquery->pluck('tanggal')->first();//2019-12-31
and the parameter are here
$cariinstasama = Barang_Keluar::where('id', $cariid)
->orWhere(function ($query) use($instansiid, $tanggal) {
$query->where('tanggal', "'$tanggal'")
->where('instansi_id', $instansiid);
});
Please any help will be appreciated, thank you.
Laravel query builder provides elegant way to put conditional clause using when() . You can put conditional clause on your query like this:
$cariinstasama = Barang_Keluar::where('id', $cariid)
->when($instansiid, function ($query, $instansiid) {
return $query->where('instansi_id', $instansiid);
})
->when($tanggal, function ($query, $tanggal) {
return $query->where('tanggal', $tanggal);
})->get();
For more info see https://laravel.com/docs/5.8/queries#conditional-clauses
You can try this as well.
$cariinstasama = Barang_Keluar::where('id', $cariid);
if($instansiid !== null)
{
$cariinstasama->where('instansi_id', $instansiid);
}
if($tanggal !== null)
{
$cariinstasama->where('instansi_id', $instansiid);
}
$result = $cariinstasama->get();
Its not clear what exactly you want.
Are you applying more than one parameter on the query if the first parameter result gives you more than one row in the database? If yes check out my approach :
$query = new Model(); // the model you want to query
if($query->where('col1', $param1)->count() > 1) // checks if the query from the 1st parameter produces more than one row in the database
$query = $query->where( // if yes apply more parameters to the query
[
['col1', $param1],
['col2', $param2]
]
);
else
$query = $query->where('col1', $param1);
$results = $query->get();
Hope it helps....
This might be an SQL limitation but I'm working on a Laravel project and so I'm posing the questions to solve what I'm trying to accomplish.
I am preforming a search on a model (and it's relationships)
Auth::user()->employers()
->where('name', 'like' $filter)
->orWhereHas('locations.location', function($query) use ($filter) {
$query->where('name', 'like', $filter);
})
->orWhereHas('locations.branches', function($query) use ($filter) {
$query->where('name', 'like', $filter);
})
->orWhereHas('locations.positions', function($query) use ($filter) {
$query->where('name', 'like', $filter);
})->get();
I would like to be able to identify which of this conditions was the one that matched the record so that I can tell the frontend, "Hey this record is being shown to you because x property nested in it matched your search critera." Where x is the condition that made it a match.
The code above returns a collection of records that matched.
I want to know where EACH of those records matched.
Now your query looks like this:
select *
from employees
where name like ?
or exists (select * from locations ...)
or exists (...)
When you add the subqueries to the SELECT part, you get boolean values:
select *,
exists (select * from locations ...) as hasLocations
exists (...) as hasBranches
...
from employees
where name like ?
or exists (select * from locations ...)
or exists (...)
You have to take a look at the whereHas implementation to find a way generating these subqueries from the relationships.
If I understand your question correctly, you simply want to show your model and say "you are seeing this because...". If that is indeed the case and the model may only have a location, or a branch, or a position when the query is complete then you may simply query it in an if statement. Assuming your 'search' criteria is $name:
$matches = array();
if($user->location == $name) {
array_push($matches, 'location');
};
if($user->branch == $name) {
array_push($matches, 'branch');
};
if($user->position == $name) {
array_push($matches, 'position');
};
return $matches;
You have basically done your query, and now need simply examine the object for which parameter satisfies your condition. If there are more than a few hard conditions though I'd search out a more object-oriented approach, though in this case a simple procedural method on the object would do. Could do this on the User model returning an array with matched values if there are more than one:
public function foundBy($name) {
$matches = array();
if($this->location == $name) {
array_push($matches, 'location');
};
if($this->branch == $name) {
array_push($matches, 'branch');
};
if($this->position == $name) {
array_push($matches, 'position');
};
return $matches;
}
This to call it:
$foundBy = $user->foundBy($name);
And should return an array.
In this way, what the method returns will tell you how the object matches by looking at the values in the array.
Hope this helped!
Is it possible to do a "BETWEEN ? AND ?" where condition LIKE in cakephp 2.5?
In cakephp 2.5 I write something like
'conditions' => ['start_date BETWEEN ? AND ?' => ['2014-01-01', '2014-12-32']]
how can I migrate that?
additionally I would write something like
'conditions' => [ '? BETWEEN start_date AND end_date'] => '2014-03-31']
Expressions
Between expression are supported out of the box, however they only support the first case without additional fiddling:
$Query = $Table
->find()
->where(function($exp) {
return $exp->between('start_date', '2014-01-01', '2014-12-32', 'date');
});
If you'd wanted to handle the second case via the between method, then you'd have to pass all values as expressions, which can easily go wrong, as they will not be subject to escaping/parameter binding in that case, you'd have to do that on your own (which is anything but recommended! See the security notes in the manual for PDO::quote()), something along the lines of:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(
$query->connection()->driver()->quote(
'2014-03-31',
\PDO::PARAM_STR
)
),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
});
That might feel a little inconvenient for such a basic SQL expression that is supported by all SQL dialects that CakePHP ships with, so you may have a reason here to use a raw SQL snippet with value bindig instead.
It should be noted however that expressions are often the better choice when it comes to for example cross dialect support, as they can be (more or less) easily transformed at compile time, see the implementations of SqlDialectTrait::_expressionTranslators(). Also expressions usually support automatic identifier quoting.
Value binding
Via manual value binding you can pretty much create anything you like. It should however be noted that whenever possible, you should use expressions instead, as they are easier to port, which happens out of the box for quite a few expressions already.
$Query = $Table
->find()
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', '2014-01-01', 'date')
->bind(':end', '2014-12-31', 'date');
That way the second case can also be solved very easily, like:
$Query = $Table
->find()
->where([
':date BETWEEN start_date AND end_date'
])
->bind(':date', '2014-03-31', 'date');
A mixture of both (safest and most compatible approach)
It's also possible to mix both, ie use an expression that makes use of custom bindings, something along the lines of this:
use Cake\Database\Expression\IdentifierExpression;
use Cake\Database\Expression\QueryExpression;
use Cake\ORM\Query;
// ...
$Query = $Table
->find()
->where(function(QueryExpression $exp, Query $query) {
return $exp->between(
$query->newExpr(':date'),
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
})
->bind(':date', '2014-03-31', 'date');
That way you could handle the second case using possibly portable expressions, and don't have to worry about quoting/escaping input data and identifiers manually.
Regular comparison using array syntax
All that being said, in the end BETWEEN is just the same as using two separate simple conditions like this:
$Query = $Table
->find()
->where([
'start_date >=' => '2014-01-01',
'start_date <=' => '2014-12-32',
]);
$Query = $Table
->find()
->where([
'start_date >=' => '2014-03-31',
'end_date <=' => '2014-03-31',
]);
But don't be mad, if you read all the way down to here, at least you learned something about the ins and outs of the query builder.
See also
Cookbook > Database Access & ORM > Query Builder > Advanced Conditions
API > \Cake\Database\Query::bind()
Currently there seems to be only two options. The core now supports this out of the box, the following is just kept for reference.
Value binding (via the database query builder)
For now the ORM query builder (Cake\ORM\Query), the one that is being retrived when invoking for example find() on a table object, doesn't support value binding
https://github.com/cakephp/cakephp/issues/4926
So, for being able to use bindings you'd have to use the underlying database query builder (Cake\Database\Query), which can for example be retrived via Connection::newQuery().
Here's an example:
$conn = ConnectionManager::get('default');
$Query = $conn->newQuery();
$Query
->select('*')
->from('table_name')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime('2014-01-01'), 'date')
->bind(':end', new \DateTime('2014-12-31'), 'date');
debug($Query->execute()->fetchAll());
This would result in a query similar to this
SELECT
*
FROM
table_name
WHERE
start_date BETWEEN '2014-01-01' AND '2014-12-31'
A custom expression class
Another option would be a custom expression class that generates appropriate SQL snippets. Here's an example.
Column names should be wrapped into identifier expression objects in order to them be auto quoted (in case auto quoting is enabled), the key > value array syntax is for binding values, where the array key is the actual value, and the array value is the datatype.
Please note that it's not safe to directly pass user input for column names, as they are not being escaped! Use a whitelist or similar to make sure the column name is safe to use!
Field between values
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
new IdentifierExpression('created'),
['2014-01-01' => 'date'],
['2014-12-31' => 'date']
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
This would generate a query similar to the one above.
Value between fields
use App\Database\Expression\BetweenComparison;
use Cake\Database\Expression\IdentifierExpression;
// ...
$between = new BetweenComparison(
['2014-03-31' => 'date'],
new IdentifierExpression('start_date'),
new IdentifierExpression('end_date')
);
$TableName = TableRegistry::get('TableName');
$Query = $TableName
->find()
->where($between);
debug($Query->execute()->fetchAll());
This on the other hand would result in a query similar to this
SELECT
*
FROM
table_name
WHERE
'2014-03-31' BETWEEN start_date AND end_date
The expression class
namespace App\Database\Expression;
use Cake\Database\ExpressionInterface;
use Cake\Database\ValueBinder;
class BetweenComparison implements ExpressionInterface {
protected $_field;
protected $_valueA;
protected $_valueB;
public function __construct($field, $valueA, $valueB) {
$this->_field = $field;
$this->_valueA = $valueA;
$this->_valueB = $valueB;
}
public function sql(ValueBinder $generator) {
$field = $this->_compilePart($this->_field, $generator);
$valueA = $this->_compilePart($this->_valueA, $generator);
$valueB = $this->_compilePart($this->_valueB, $generator);
return sprintf('%s BETWEEN %s AND %s', $field, $valueA, $valueB);
}
public function traverse(callable $callable) {
$this->_traversePart($this->_field, $callable);
$this->_traversePart($this->_valueA, $callable);
$this->_traversePart($this->_valueB, $callable);
}
protected function _bindValue($value, $generator, $type) {
$placeholder = $generator->placeholder('c');
$generator->bind($placeholder, $value, $type);
return $placeholder;
}
protected function _compilePart($value, $generator) {
if ($value instanceof ExpressionInterface) {
return $value->sql($generator);
} else if(is_array($value)) {
return $this->_bindValue(key($value), $generator, current($value));
}
return $value;
}
protected function _traversePart($value, callable $callable) {
if ($value instanceof ExpressionInterface) {
$callable($value);
$value->traverse($callable);
}
}
}
You can use one of following 2 methods.
Method 1 :
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where(function ($exp, $q) use($start_date,$end_date) {
return $exp->between('start_date', $start_date, $end_date);
});
$result = $query->toArray();
Method 2:
$start_date = '2014-01-01 00:00:00';
$end_date = '2014-12-31 23:59:59';
$query = $this->Table->find('all')
->where([
'start_date BETWEEN :start AND :end'
])
->bind(':start', new \DateTime($start_date), 'datetime')
->bind(':end', new \DateTime($end_date), 'datetime');
$result = $query->toArray();
I'm using it like this
$this->Table->find()->where(['data_inicio BETWEEN '.'\''.$data_inicio.'\''.' AND .'\''.$data_final.'\''.' ']);
Hello guys please use this query to get data on the basis of range of value
$query = $this->Leads->find('all',
array('conditions'=>array('postcode BETWEEN '.$postcodeFrom.' and'.$postcodeTo.''), 'recursive'=>-1));
debug($query);
print_r($query->toArray());