PhalconPHP bind params and oerder by - sql-order-by

Here is the code what I've tried
$conditions = "category = :id: AND status = :status: ORDER BY :order: LIMIT 3";
$parameters = array(
"id" => $cat_id,
"status" => 1,
"order" => "title ASC",
);
$posts = Posts::find(array(
$conditions,
"bind" => $parameters
));
Everything is fine except order by. Can you please help me to find out the proper way to use order by in PhalconPHP?

"bind" and "order" are separate parameters:
$conditions = "category = :id: AND status = :status:";
$parameters = array(
"id" => $cat_id,
"status" => 1,
);
$posts = Posts::find(array(
"conditions" => $conditions,
"bind" => $parameters,
"order" => "title ASC",
"limit" => 3
));
this is clean and reliable approach - this way you have in your conditions only striclty conditions. You can change your limit/order based on request params without touching condition string.

Related

Laravel DB::raw() to take dynamic inputs

I have query where I am getting the sum of price by suppliers. The below query works fine.
private function integrationsSpendBySupplier(array $suppliers)
{
$totalBySupplier = DB::table('analytics')
->whereIn('source', $suppliers)->select(
'source',
DB::raw('sum(price) as total')
)
->groupBy('source')
->get();
return [
'title' => 'Spend per Supplier',
'rows' => 12,
'type' => 'bar',
'data' => [
'labels' => $totalBySupplier->map(fn ($supplier) => $supplier->source),
'datasets' => [
[
'label' => 'Total Spending',
'data' => $totalBySupplier->map(fn ($supplier) => $this->stringToFloat($supplier->total))
],
]
],
'hasToolTip' => true
];
}
However, I would also like to add more items to the DB::raw() call like so:
DB::raw('sum(price + shipping + tax + something_else) as total')
But these values will be dynamic so it could be all or none of additional params (price will always be there though).
Any thoughts?
You can build the SUM() string using basic PHP string and apply that string to the query.
for example
$price = '';
if (priceRequired())
$price = "price ";
$shipping = '';
if (requiresShipping())
$shipping = ", shipping";
// $shipping = requiresShipping() ? ", shipping" : ""; if you're familiar with this syntax
...
DB::raw("sum($price $shipping ...etc) as total");
as a result, the final string should be like price, shipping, tax or price depending on the above conditions.
Note: be careful about the comma's place in the string, this may cause query exceptions

Laravel Query Builder Issue Remove Null Values

Hi all you smart individuals i'm hitting a solid wall here with someone else code that i'm trying to fix a issue.
The issue is that when this query builder has got all the results there seems to be some coming back with null values and i'm not sure how to remove them before I paginate the data, I know how to do it if it was a collection however maybe some of you might be-able to help me.
so currently the logic goes into this pagination
$return = $tld->paginate($request->get('limit'))->toArray();
$tld being the eloquent builder.
Which then gets sent into this function that was created..
$return = $this->makePagination($return);
public function makePagination($object = [], $filters = []) {
return [
'data' => [
'items' => $object['data'],
'pagination' => [
'from' => $object['from'],
'to' => $object['to'],
'total' => $object['total'],
'per_page' => $object['per_page'],
'first_page' => [
'number' => 1,
'url' => $object['first_page_url']
],
'last_page' => [
'number' => $object['last_page'],
'url' => $object['last_page_url']
],
'next_page' => [
'number' => $object['current_page'] + 1,
'url' => $object['next_page_url']
],
'prev_page' => [
'number' => $object['current_page'] - 1,
'url' => $object['prev_page_url']
]
],
'params' => $filters
]
];
}
But then i'm getting a response like this with Null values and I would like to remove them before any of this pagination happens
{
"data": {
"items": [
{
"id": 13771,
},
null,
{
"id": 4125,
},
Side note if I run $tld->get() I can see all the results and there are null values in there so if anyone can show me how to remove the null values that would be a great help <3 you all if you can help me ...
Update
Ive also tried $tld->get()->filter(); and thats also not removing the null values I still get this response
[
{
"id": 13771,
},
null,
{
"id": 789,
}
]
I think I fixed it with a little hack
$filtered = collect(array_values(array_filter($tld->get()->toArray())));
return $this->paginate($filtered, $request->get('limit') ?? 15 , $page = null, $options = []);
and then created a collection paginator
public function paginate($items, $perPage = 15, $page = null, $options = [])
{
$page = $page ?: (Paginator::resolveCurrentPage() ?: 1);
$items = $items instanceof Collection ? $items : Collection::make($items);
return new LengthAwarePaginator($items->forPage($page, $perPage), $items->count(), $perPage, $page, $options);
}
#Bob Hiller Please use whereNotNull in query to remove null entries.
$tld=$query->get();
$tld->filter(function ($value) { return !is_null($value); });
$return = $tld->paginate($request->get('limit'))->toArray();

Map array values to collection of items

How would one do the following elegantly with laravel collections ?
Map the values of the $baseMap as keys to the collection.
The baseMap :
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
The collection :
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
//...
]);
The end result :
$result =[
[
'new_name' => 'name1',
'new_year' => '1000',
],
[
'new_name'=> 'name2',
'new_year' => '2000',
],
];
I know how to do it in plain php , just wondering what a nice collection version would be. Thanks!
I tried to find collection methods, or php functions, but without success. Some dirty code that works with different keys from both sides (items and basemap).
$result = $items->map(function($item) use ($baseMap) {
$array = [];
foreach($baseMap as $oldKey => $newKey){
if(isset($item[$oldKey])){
$array[$newKey] = $item[$oldKey];
}
}
return $array;
});
$result = $result->toArray();
Thanks to #vivek_23 and #IndianCoding for giving me idea's I ended up with the following :
I made a small edit to make sure the mapping and the items keys lined up.
so you don't have to worry of misalignment and all in laravel collection !
$baseMap = collect($baseMap)->sortKeys();
$result = $items->map(function ($item) use ($baseMap) {
return $baseMap->values()
->combine(
collect($item)->sortKeys()->intersectByKeys($baseMap)
)
->all();
});
Use intersectByKeys to filter your baseMap keys with $items values.
$result = $items->map(function($item,$key) use ($baseMap){
return array_combine(array_values($baseMap),collect($item)->intersectByKeys($baseMap)->all());
});
dd($result);
Update:
In a pure collection way,
$baseMapCollect = collect($baseMap);
$result = $items->map(function($item,$key) use ($baseMapCollect){
return $baseMapCollect->values()->combine(collect($item)->intersectByKeys($baseMapCollect->all())->values())->all();
});
dd($result);
Here are my two cents, using map. Don't know how dynamic your collection should be, but knowing the keys I would do the following:
$baseMap = [
'name' => 'new_name',
'year' => 'new_year',
];
$items = collect([
[
'name' => 'name1',
'year' => '1000',
'not_in_basemap' => 'foo'
],
[
'name' => 'name2',
'year' => '2000',
'not_in_basemap' => 'foo'
],
])->map(function($item, $key) use ($baseMap) {
return [
$baseMap['name'] => $item['name'],
$baseMap['year'] => $item['year']
];
});

Laravel5.5 adding columns to a collection from a second one

I have a sql request concerning admin :
$admin = Admin::findOrFail(Auth::guard('admin')->user()->id);
from this sql request I also manage to get the users of the admin ...
$users = $admin->users;
Each users must follow training sessions. and I must calculate it by using SQL requests for each users ... So i wrote this foreach statement
foreach ($users as $user) {
$todo = User::select() .....where('users.id' = $user->id)->get();
$done = User::select() .....where('users.id' = $user->id)->get();
$totalTimes = $todo->toBase()->sum('dureeformation');
$spendTimes = $done->toBase()->sum('dureeformation');
$remainingTimes = $totalTimes - $spendTimes;
$timeData[] = ['id' => $user->id, 'totalTime' => $totalTimes, 'spendTime' => $spendTimes, 'remainingTime' => $remainingTimes];
}
the totalTimes, spendTimes and remainingTimes are operations on Collections and i get expected results ...
$users->each(function ($record) use ($timeData) {
$record['totalTime'] = $timeData[$record['id']]['totalTime'];
$record['spendTime'] = $timeData[$record['id']]['spendTime'];
$record['remainingTime'] = $timeData[$record['id']]['remainingTime'];
//dd($record['totalTime']);
});
After this :
$timeData = collect($timeData);
$timeData= $timeData->keyBy('id');
$users = collect($users->toArray());
I have an issue here :
$users->each(function ($record) use ($timeData) {
$record['totalTime'] = $timeData[$record['id']]['totalTime'];
$record['spendTime'] = $timeData[$record['id']]['spendTime'];
$record['remainingTime'] = $timeData[$record['id']]['remainingTime'];
//var_dump($record);
});
$record in the function gives me what i expect ... the var_dump($records) added columns where it was expected but i can't take those results out of the function.
I tried to do this :
$variable = $users->each(function ($record) use ($timeData)...
dd($variable)
but unsuccessfully ...
Looks to me like your $timeData array is built differently than you access it. In your code you are doing
$timeData[] = [
'id' => $user->id,
'totalTime' => $totalTimes,
'spendTime' => $spendTimes,
'remainingTime' => $remainingTimes,
];
which will produce an array like this
[
0 => [
'id' => 17,
'totalTime' => 5,
'spendTime' => 4,
'remainingTime' => 3
],
1 => [
'id' => 17,
'totalTime' => 7,
'spendTime' => 5,
'remainingTime' => 2
]
]
but what you actually want is to have the id as index, right? Then you'd have to build the array this way:
$timeData[$user->id] = [
'totalTime' => $totalTimes,
'spendTime' => $spendTimes,
'remainingTime' => $remainingTimes,
];
or, as an alternative, perform a different lookup:
$users->each(function ($record) use ($timeData) {
$times = array_first($timeData, function ($value, $key) use ($record) {
return $value['id'] === $record['id'];
});
$record['totalTime'] = $times['totalTime'];
$record['spendTime'] = $times['spendTime'];
$record['remainingTime'] = $times['remainingTime'];
});
Both solutions have pros and cons, though. On the one hand, using the user identifier as the index will produce a huge array that is only filled partially. On the other hand, the second solution is a bit slower. As long as you are not going to deal with thousands of entries in the $timeData array, this won't be an issue, though.

Yii - How to use conditions like where and limit

I use findAll() like this:
$l = SiteContentRelated::model()->findAll('content_1=:c', array(':c' => $id));
How I can add condition to this?
Like as LIMIT 5 or anything?
Use CDbCriteria to specify more detailed criteria:
$criteria = new CDbCriteria;
$criteria->condition = 'content_1=:c';
$criteria->limit = 5;
$criteria->params = array(':c' => $id);
$l = SiteContentRelated::model()->findAll($criteria);
or pass an array to findAll which will be converted to a CDbCriteria:
$l = SiteContentRelated::model()->findAll(array(
'condition' => 'content_1=:c',
'limit' => 5,
'params' => array(':c' => $id),
));
When you specify a LIMIT, it's a good idea to also specify ORDER BY.
For filtering based on model attributes, you can also use findAllByAttributes:
$l = SiteContentRelated::model()->findAllByAttributes(array(
'content_1' => $id,
), array(
'limit' => 5,
));

Resources