Lumen - pagination and result editing - php

I'm new to Lumen and trying to make a simple REST API app. I want one of the endpoints to be able to display all records from a "storeItems" table but add a field to each record with its' categories and paginate them.
So at the moment I have the usual
$products = DB::table('storeItems as i')
->where('i.B2BAvailable', '=', '1')
->select('i.title','i.EAN','i.vendor','i.productType','i.ID as productID','i.releaseDate',DB::raw('(CASE WHEN (i.releaseDate > NOW()) THEN 1 ELSE 0 END) AS announced'))
->orderBy('i.releaseDate', 'desc')
->paginate(100);
return response()->json($products);
This gives out the expected result, but if I want to iterate over the results and add a field from a different table...like this:
foreach($products as $product) {
$genres = DB::table('sCategoryConnector as ggc')
->join('sCatGenre as gg','gg.ID','=','ggc.ID_sCatGenre')
->where('ggc.EAN', '=', DB::raw("'".$product->EAN."'"))
->select('gg.tag')
->orderBy('gg.ID', 'asc')
->get();
if (count($genres) > 0) {
$i=0;
foreach($genres as $genre) {
//$product['genres'][$i] = $genre['tag'];
$propName = 'genre'.$i;
$product->genres->$propName = $genre->tag;
$i++;
}
}
}
But Lumen is outputting: Creating default object from empty value error and marking this line:
$product->genres->$propName = $genre->tag;
What am I doing wrong? Thanks up front.

So I was rushing a bit...should have replaced assigning genres like this:
if (count($genres) > 0) {
$i=0;
$product->genres = $genres;
/*
foreach($genres as $genre) {
//$product['genres'][$i] = $genre['tag'];
$propName = 'genre'.$i;
$product->genres->$propName = $genre->tag;
$i++;
}
*/
}
So the correct way to assign a new property to a StdClass object....
$product->genres = $genres;

Related

I need a loop inside a model query

How can I loop in a model?
I have:
SitemapGenerator::create(config('app.url'))
->configureCrawler(function (Crawler $crawler) {
$crawler->setMaximumDepth(4);
})
->add(Url::create('https://mydomain/mycustompage/'))
->getSitemap()
->writeToFile(public_path('sitemap.xml'));
I need someway to loop this: ->add(Url::create('https://mydomain/mycustompage/'))
I want to get info from my DB like this:
$all_active_products = DB::table('products')->select('slug')->where('is_active',1)->whereNull('deleted_at')->get();
And I want something like this:
$all_active_products = DB::table('products')->select('slug')->where('is_active',1)->whereNull('deleted_at')->get();
SitemapGenerator::create(config('app.url'))
->configureCrawler(function (Crawler $crawler) {
$crawler->setMaximumDepth(4);
})
foreach ($all_active_products as $a){
->add(Url::create('https://mydomain/mycustompage/'.$a->slug))
}
->getSitemap()
->writeToFile(public_path('sitemap.xml'));
I am using this package.
$products = Product::all();
//or
$products = Product::with('categories')->where('status', 1)->whereRaw('quantity is not null AND quantity > 0 ', 1)->whereNotNull('price');
//or
$products = Product::select([
'*',
DB::raw('(CASE
WHEN sale_price is not null AND ( now() = sale_from THEN sale_price
ELSE price
END) product_price')
])->where('status', 1)->whereNotNull('price');
//now for loop
foreach ($products as $key=>$product) {
echo $product->name;
}

CakePHP 3.8 convert array to Cake\ORM\Entity

I am currently involved in a CakePHP project and do not know how I can pass a modified query/array to a paginator.
Here is my controller:
public function index($fooElement = '')
{
$query = $this->Properties->find()->where(['fooElement' => $fooElement]);
//The fooFunction needs an array cause for an internal call of cakes HASH::NEST function
$data= $this->FooModel->_fooFunction($query->enableHydration(false)->toList();
//Error: Not a paginable object
$data = $this->paginate($data)
$this->set(compact('fooElement', 'data'));
$this->set('_serialize', ['data']);
if (empty($fooElement)) {
$this->render('otherView');
}
}
EDIT: Here is the fooFunction:
public function _fooFunction($data)
{
$out = [];
$cache = [];
$nested = Hash::nest($data, ['idPath' => '{n}.id', 'parentPath' => '{n}.parent_id']);
$out = $this->_setOrderAndLevel($nested);
return $out;
}
protected function _setOrderAndLevel($items, $level = 0, $number = 0)
{
$out = [];
$items = Hash::sort($items, '{n}.orderidx');
foreach ($items as $item) {
$item['level'] = $level;
if (!empty($item['children'])) {
$children = $item['children'];
unset($item['children']);
$out[] = $item;
$out = array_merge($out, $this->_setOrderAndLevel($children, $level + 1));
} else {
$out[] = $item;
}
}
return ($out);
}
The _fooFunction takes the casted database query, makes some adjustments, adds two new properties and returns a nested Array. It maps id with parent_id in order to get children and a level description. The level description will be used for indentations in the view to display a hierarchical order.
IMPORTANT NOTICE: I am already beware of TreeBehavior in CakePHP but the problem is that our database has no left/right fields and I am not able to add them. Within this project I have to choose this way.
However $data contains exactly what I want but I need to transform it into a compatible object for pagination.
EDIT: Thanks to ndm I could build a paginable object with the necessary constraints. The last problem I still have in front of me is to merge all children and possible sub-children. A parent can have nth children and also a children can sometimes have nth sub-children. Therefore I solved this with a recursive call of my _setOrderAndLevel function within the fooFunction.
This is the current structure:
array(
[0] = fooEntity(
id = 1,
orderidx = 1,
parentId = null,
level = 0,
children(
id = 2,
orderidx = 2,
parentId = 1,
level = 1
children(
id = 3,
orderidx = 3,
parentId = 2,
level = 2
........
But it should be this:
array(
[0] = fooEntity(
id = 1,
orderidx = 1,
parentId = null
level = 0
[1] = fooEntity(
id = 2,
orderidx = 2,
parentId = 1,
level = 1
[2] = fooEntity(
id = 3,
orderidx = 3,
parentId = 2,
level = 2
........
I tried to build a second result formatter but it does not work:
...
return $results
->nest('id', 'parent_id', 'children')
->map($decorate);
})
->formatResults(function (\Cake\Collection\CollectionInterface $results) {
return $results->map(function ($data) {
call_user_func_array('array_merge', $data);
});
});
Maybe a "combine->" call could be the solution but I am not sure.
Any help is welcome
Generally if you need to format the results in some way, you should most likely use a result formatter, in order to be able to keep query object intact, and rom looking at the resulting format that your function produces, that is what you should use in this case, a result formatter.
If you need the ordering you could do that on SQL level already, and for nesting the results you could use the result collection's nest() method, ie you could ditch using the Hash class:
$query = $this->Properties
->find()
->where(['fooElement' => $fooElement])
->order(['orderidx' => 'ASC'])
->formatResults(function (\Cake\Collection\CollectionInterface $results) {
$fold = function ($rows, $level = 0) use (&$fold) {
$folded = [];
foreach ($rows as $row) {
$row['level'] = $level;
$children = $row['children'] ?: null;
unset($row['children']);
$folded[] = $row;
if ($children) {
$folded = array_merge(
$folded,
$fold($children, $level ++)
);
}
}
return $folded;
};
$nested = $results->nest('id', 'parent_id', 'children');
$folded = $fold($nested);
return collection($folded);
});
Note that you must return an instance of \Cake\Collection\CollectionInterface from the result formatter. The docs say that returning an(y) iterator would be enough, but as soon as there are additional formatters appended that expect a collection, things would break.
See also
Cookbook > Database Access & ORM > Query Builder > Adding Calculated Fields
Cookbook > Collections > Working with Tree Data

Getting multiple fields from database to an array

I wrote an api call in my Symfony project that returns all fields from my entity with the query defined below..
Now, I need to define just three fields like 'id', 'name', 'value' and to pull values from that fields that are currently stored in a database.
public function getChartData() {
$myResults = $this->getMyRepository()
->createQueryBuilder('s')
->groupBy('s.totalCollected')
->orderBy('s.id', 'ASC')
->getQuery()
->getArrayResult();
$result = array("data" => array());
foreach ($myResults as $myResult => $label) {
$result['data'][$schoolResult] = $label["id"];
$result['data'][$schoolResult] = $label["name"];
$result['data'][$schoolResult] = $label["totalCollected"];
}
}
The problem is it return just totalCollected field.
One of errors are Call to a member function getId() on array and so on, and I can't figure out a way to pull data from db...
I cannot see in your code where $schoolResult come from but lets guess it string key of some sort.
Notice you trying to set 3 value on the same key so only the last one remains.
Look at:
$a = array();
$a["key"] = 4;
$a["key"] = 6;
It is simple to see that $a["key"] will contains 6 and not 4 or both.
When you do:
foreach ($myResults as $myResult => $label) {
$result['data'][$schoolResult] = $label["id"];
$result['data'][$schoolResult] = $label["name"];
$result['data'][$schoolResult] = $label["totalCollected"];
}
You override the data in $result['data'][$schoolResult] therefor only try totalCollected is there as the last one to set.
In order to fix that you can use:
foreach ($myResults as $myResult => $label) {
$result['data'][$schoolResult]["id] = $label["id"];
$result['data'][$schoolResult]["name"] = $label["name"];
$result['data'][$schoolResult]["totalCollected"] = $label["totalCollected"];
}
Hope that helps!

Codeigniter select distinct and passing the list of variables

Just want to SELECT DISTINCT country FROM table WHERE user_id=$user_id, pass the country list from model to controller and then pass the JSON representation of the country list but as I am a newbie in Codeigniter I am not sure if wrote the query correctly and if I return the list or a single value. Could you please check my code.
Model:
public function did_get_country_list($user_id) {
$this->db->distinct('country');
$this->db->where('user_id',$user_id);
$query = $this->db->get('table');
if ($query->num_rows() >= 1) {
foreach ($query->result() as $row)
{
$country = $row->country;
}
return $country;
}
else{
return false;
}
}
Controller:
$country = $this->model_users->did_get_country_plans($user_id);
echo json_encode($country);
Your code looks almost ok to me, but I think you should change 2 lines:
1) Remove the check for num_rows before the actual query.
2) To return an array of countries, add [] at the end of $country to push the new values.
So, instead of this snippet:
if ($query->num_rows() >= 1) {
foreach ($query->result() as $row)
{
$country = $row->country;
}
return $country;
}
else{
return false;
}
You would have:
$country = false;
foreach ($query->result() as $row)
{
$country[] = $row->country;
}
return $country;

Trouble ordering information when pulled from the database in zend.

So I am having trouble getting the information I pull from the database order according to the id in my database. I wrote the following function based on a tutorial in a book ('Pro Zend Framework Techniques' published by Apress) and the book is riddled with typos and mistakes so i'm hoping it is something im just overlooking.
public function getRecentArticles ($count = 99, $namespace = 'article')
{
$select = $this->select();
$select->order = 'id DESC';
$select->where('namespace = ?', $namespace);
$select->limit($count);
$results = $this->fetchAll($select);
if ($results->count() > 0) {
$articles = array();
foreach ($results as $result) {
$articles[$result->id] = new Rt_Content_Item_Article($result->id);
}
return $articles;
} else {
return null;
}
}
As you can see, I am trying to arrange the articles in descending order based on the ID field in the database. Any advice would be great.
Thanks.
$select = $this->select ()
->order ('id DESC')
->where ('namespace = ?', $namespace)
->limit ($count);
order is a function, same as where and limit. So your order line should be:
$select->order('id DESC');

Categories