Modx: getCollection query is not working - php

Inside my processor class I have a statement that grabs all the projects from a db table and formats them to be displayed. This method does not work and halts at the getCollection call.
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public function initialize() {
return parent::initialize();
}
public function process() {
$result = $this->modx->getCollection('ManagerProjects');
$project_names = array();
foreach ($result as $row) {
$projects = unserialize($row->get('manager_projects'));
foreach($projects as $short_code => $project) {
$project_names[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
}
return '{"total":' . count($project_names) . ',"results":' . $this->modx->toJSON($project_names) . ',"success":true}';
}
...
}
This code that uses plain SQL does work:
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public function initialize() {
return parent::initialize();
}
public function process() {
$leadersql = "SELECT * FROM `modx_manager_projects`";
$query = $this->modx->query($leadersql);
$project_names = array();
while ($row = $query->fetch(PDO::FETCH_ASSOC)) {
$projects = unserialize($row['manager_projects']);
foreach($projects as $short_code => $project) {
$project_names[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
};
return '{"total":' . count($project_names) . ',"results":' . $this->modx->toJSON($project_names) . ',"success":true}';
}
...
}
I use similar method to the first which saves ManagerProjects and works fine, so I don't think it has to do with the model declaration. I could easily just use the second method above since it seems to work, but I want to use the best method.
What is wrong with the first method?
Is the first method the proper way to implement SQL in the Modx processor? Or is there a better way?

We can do this task easier a little bit.
#Vasis is right but we can use base prepareRow method instead of reloading iterate method:
<?php
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public $classKey = 'ManagerProjects';
protected $projects = array();
public function prepareRow(xPDOObject $object) {
$_projects = unserialize($object->get('manager_projects'));
foreach($_projects as $short_code => $project) {
$this->projects[] = array('project_name' => $project, 'project_short_code' => $short_code);
}
return parent::prepareRow($object);
}
public function outputArray(array $array,$count = false) {
$count = count($this->projects);
return parent::outputArray($this->projects,$count);
}
}
return 'GlobalLinkSettingsProcessor';
There we can see one of modx ‘features’. In modObjectGetListProcessor process method we can see this:
public function process() {
$beforeQuery = $this->beforeQuery();
if ($beforeQuery !== true) {
return $this->failure($beforeQuery);
}
$data = $this->getData();
$list = $this->iterate($data);
return $this->outputArray($list,$data['total']);
}
getData method returns a list of objects and it goes to iterate method (where we can check if the object is accessible and change the list of these objects on demand). If you don't have access to some of objects we'll get changed list. And it goes to outputArray method but second parameter is still old for it. So you should count them again.
This is solution is quite well but you tried to get data which is stored in object's field. So afterIteration method will be unusable for further extension in my version of processor. But who cares? :)
P.S.: About your first version of processor. modObjectGetList processor is ready for getting collection. So you have not to use getcollection method. Just add proper classKey property to it.
Another way is in modProcessor extension. It gives to you a base structure. But you can make your own kind of stuff.

Because you do it wrong! Just see this. The right way to do it, is something like this:
<?php
class GlobalLinkSettingsProcessor extends modObjectGetListProcessor{
public $classKey = 'ManagerProjects';
public function iterate(array $data) {
$list = array();
$list = $this->beforeIteration($list);
$this->currentIndex = 0;
/** #var xPDOObject|modAccessibleObject $object */
foreach ($data['results'] as $object) {
if ($this->checkListPermission && $object instanceof modAccessibleObject && !$object->checkPolicy('list')) continue;
$projects = unserialize($object->get('manager_projects'));
foreach($projects as $short_code => $project) {
$objectArray = array('project_name' => $project, 'project_short_code' => $short_code);
if (!empty($objectArray) && is_array($objectArray)) {
$list[] = $objectArray;
$this->currentIndex++;
}
}
}
$list = $this->afterIteration($list);
return $list;
}
}

Related

Having trouble understanding why my Closure wasn't working

I have a controller in laravel, AppExportController. In one of my functions on that controller, I iterate over many records and return a file download. I decided I wanted to create a little function so I could cache a certain thing, a Zone Name in this instance.
This was my first attempt at writing a function to cache the zone names (the getZoneName function obviously):
<?php
namespace App\Http\Controllers;
class AppExportController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth');
$this->middleware('client.approved');
}
public function prices(Request $request) {
$user = Auth::user();
...
$zoneNameCache = [];
function getZoneName($zoneId) use (&$zoneNameCache) {
try {
if (!empty($zoneNameCache[$zoneId])) {
return $zoneNameCache[$zoneId];
} else {
$zone = ServiceZone::find($zoneId);
$zoneNameCache[$zoneId] = $zone->name;
return $zone->name;
}
} catch(Exception $e) {
return '';
}
};
$prices = []; // I actually do a database query here, don't worry about that
$records = [];
foreach($prices as $price) {
// output to $records here
$records[] = [
...
getZoneName($price->service_zone_id),
...
];
}
return response();
}
}
This was making that route 500 error, and I tracked it down to being for sure the closure aspect of the function -- when I took out the use (&$zoneNameCache) part, it worked (but didn't cache anything of course).
So I tried another thing -- assigning the function to a variable instead. And that worked! With the closure, and caching was working!
<?php
namespace App\Http\Controllers;
class AppExportController extends Controller {
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct() {
$this->middleware('auth');
$this->middleware('client.approved');
}
public function prices(Request $request) {
$user = Auth::user();
...
$zoneNameCache = [];
$getZoneName = function ($zoneId) use (&$zoneNameCache) {
try {
if (!empty($zoneNameCache[$zoneId])) {
return $zoneNameCache[$zoneId];
} else {
$zone = ServiceZone::find($zoneId);
$zoneNameCache[$zoneId] = $zone->name;
return $zone->name;
}
} catch(Exception $e) {
return '';
}
};
$prices = []; // I actually do a database query here, don't worry about that
$records = [];
foreach($prices as $price) {
// output to $records here
$records[] = [
...
$getZoneName($price->service_zone_id),
...
];
}
return response();
}
}
I don't know why the second one should work but not the first one. Can anyone shed light on this?
Without assigning it to a variable, or returning it, it is not a closure.
This way you have function declaration, within another function or method in this case.
Which is not allowed, and therefore will give you a 500 for sure.
If you check your php error_log and probably your laravel log. It will tell you that.
If your do not want to assign it to a variable at that point, you could return it immediately
return function().......

PHP OOP - return arrays into class(?)

I'm trying to use OOP ways. I have bunch of methods that return same format of array. I want to guarantee that user of this class knows what will be returned. How would I go about doing that? Please forgive me as I'm not sure of correct terminologies to describe my problem.
class myModel {
public function getArray1(){
$data = array();
$id = array();
....
return array('data'=>$data, 'id'=>$id); <== HOW TO GUARANTEE RETURN FORMAT
};
public function getArray2(){
$data = array();
$id = array();
....
return array('data'=>$data, 'id'=>$id); <== HOW TO GUARANTEE RETURN FORMAT
};
public function getArray3(){
$data = array();
$id = array();
....
return array('data'=>$data, 'id'=>$id); <== HOW TO GUARANTEE RETURN FORMAT
};
}
You can try to define additional class for returning value:
class returnArray {
$data = array();
$id = array();
function construct($data,$id) {
$this->data = $data;
$this->id = $id;
}
}
//...
public function getArray1(){
$data = array();
$id = array();
....
return new returnArray('data'=>$data, 'id'=>$id);
};
Then You can add accessors to the returnArray class or leave it as public if You want or even implement __toString() if necessary.

How to call and view an array in a function

I'm new to PHP and Kohana.
I would like to know how to call an array in a function.
I'm having the variable $productlist and I would like to add more elements into it with a function.
public $productlist = array();
public function action_index()
{
$product = new Product("Laptop","HP4897");
$product2 = new Product("TV","Samsung 8773");
$productlist[] = product;
$productlist[] = product2;
$this->add_product_to_array("Ebook","Everything you want to know");
$this->show_productlist();
}
public function add_product_to_array($product_name, $product_description)
{
$newproduct = new Product($product_name, $product_description);
array_push($productlist,$newproduct);
}
public function show_productlist(){
foreach($productlist as $key => $value)
{
print_r($value->get_product_name().'</br>');
}
}
and this is the exception i'm getting:
*ErrorException [ Warning ]: array_push() expects parameter 1 to be array, null given*
if I'm adding foreach($this->productlist as $key => $value), it tells me it can't find productlist.
Product.php
class Product {
private $_product_name;
private $_product_description;
function __construct($name,$description)
{
$this->_product_name = $name;
$this->_product_description = $description;
}
public function get_product_name()
{
return $this->_product_name;
}
//etc
PHP Classes and Objects - The Basics
Inside the class when you access the $productlist array you need to use $this->productlist. You seem to have known this in the Product class. What happened?

display results in kostache

Ok I just started kostache and I would like to display the results i got from the database using orm in kohana 3.3. I know how to display them using foreach statement but when using kostache it's way different. So here's my code.
APPATH/classes/controller/album.php
class Controller_Album extends Controller
{
public function action_index()
{
$view = Kostache_Layout::factory();
$this->response->body($view->render(new View_Pages_Album_List));
}
}
APPATH/classes/view/pages/album/list.php
class View_Pages_Album_List {
public $title = 'List of Music';
public function album_list()
{
$albums = ORM::factory('Album_Information')->find_all();
return $albums;
}
}
APPATH/templates/pages/album/list.mustache
{{album_list}}
How would i display the resulst?. How would you do this in kostache?
Thanks and more power.
Well Nevermind I got it working..
public function album_list()
{
$albums = ORM::factory('Album_Information')->find_all();
$album_info = array();
foreach ($albums as $a)
{
$album = array('album' => array('artist' => $a->Artist, 'album_name' => $a->Album_Name,));
$album_info[] = $album;
}
return $album_info;
}

save() function Zend Framework

I have found this function in the documentation from Zend, more specific in the Create model and Database Table section ( http://framework.zend.com/manual/1.12/en/learning.quickstart.create-model.html ).
This is in the Application_Model_GuestbookMapper:
public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);
if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id));
}
}
and now i would like to integrate this into my controller, but i have no idea how?
I created an instance of the mapper and tried to pass the info from my decoded json string to it, but I still get errors...:
public function indexAction()
{
$mapper = new Application_Model_GuestbookMapper();
$db = Zend_Db_Table_Abstract::getDefaultAdapter();
$json = file_get_contents('http://data.appsforghent.be/poi/apotheken.json');
$data = Zend_Json::decode($json);
foreach($data['apotheken'] as $row)
{
$mapper->save();
}
}
I know i have to pass the $data to the save() function but I have no idea how... The model won't fit the json-url, I just wanted to show how I retrieve and decode the json.
Can anybody help me?
What you need to pass in to the $mapper->save(); is an instance of Application_Model_Guestbook. So hopefully you have a class Application_Model_Guestbook in which you define the possibility to set a data array as its attributes, for example like this:
class Application_Model_Guestbook {
private $email,$comment,$created;
public function __construct($data) {
$this->email = $data['email'];
// etc add other variables
}
public function getEmail() {
return $this->email;
}
}
Then to call that, use:
foreach($data['apotheken'] as $row)
{
$guestbook = new Application_Model_Guestbook($row);
$mapper->save($guestbook);
}
I have not tested this specifically, but it should give you an idea of how to achieve what you want to do.

Categories