I have successfully implemented the pagination box in a component front end listing template. however, when i try to set the limit of listing items, it won't work, i wonder what is missed out.
in the model
var $_total = null;
/**
* Pagination object
* #var object
*/
var $_pagination = null;
function __construct(){
parent::__construct();
$mainframe = JFactory::getApplication();
// Get pagination request variables
$limit = $mainframe->getUserStateFromRequest('global.list.limit', 'limit', $mainframe->getCfg('list_limit'), 'int');
$limitstart = JRequest::getVar('limitstart', 0, '', 'int');
// In case limit has been changed, adjust it
$limitstart = ($limit != 0 ? (floor($limitstart / $limit) * $limit) : 0);
$this->setState('limit', $limit);
$this->setState('limitstart', $limitstart);
}
function _buildQuery(){
$query = ' SELECT * '
. ' FROM #__event '
.'Where published = 1'
;
return $query;
}
function getData() {
// if data hasn't already been obtained, load it
if (empty($this->_data)) {
$query = $this->_buildQuery();
$this->_data = $this->_getList($query, $this->getState('limitstart'), $this->getState('limit'));
}
return $this->_data;
}
function getTotal(){
// Load the content if it doesn't already exist
if (empty($this->_total)) {
$query = $this->_buildQuery();
$this->_total = $this->_getListCount($query);
}
return $this->_total;
}
function getPagination(){
// Load the content if it doesn't already exist
if (empty($this->_pagination)) {
jimport('joomla.html.pagination');
$this->_pagination = new JPagination($this->getTotal(), $this->getState('limitstart'), $this->getState('limit') );
}
return $this->_pagination;
}
in the views/view.html.php (full version of this document)
class EventViewListing extends JViewLegacy
{
// Overwriting JView display method
function display($tpl = null)
{
$model= & JModelLegacy::getInstance('Event','EventModel');
$pagination = $model->getPagination();
$this->assignRef('pagination', $pagination);
$JDoc =& JFactory::getDocument();
$db = JFactory::getDBO();
$sql = "SELECT * FROM #__event WHERE published = 1 ORDER BY id DESC";
$db->setQuery($sql);
$rows = $db->loadObjectList();
$sql2 = "SELECT * FROM #__user_usergroup_map WHERE group_id = 5 or group_id = 8";
$db->setQuery($sql2);
$rows2 = $db->loadObjectList();
$this->assignRef('rows',$rows);
$this->assignRef('rows2',$rows2);
// $JDoc->setTitle(' ');
// Display the view
parent::display($tpl);
}
}
in the default.php
<form action="<?php echo JRoute::_('index.php?option=com_event'); ?>" method="post" name="adminForm">
<?php echo $this->pagination->getListFooter(); ?>
<input type="submit" name="submit" value="GO!" />
</form>
hope someone could help
thank you!
The limits need to also be used in the queries to limit the number of records that are displayed to the page that you are on. Typically this can be done in the setQuery function, which allows a second and third parameter to set the limit size and start position.
$sql = "SELECT * FROM #__event WHERE published = 1 ORDER BY id DESC";
$db->setQuery($sql, $model->getState('limitstart'), $model->getState('limit'));
$rows = $db->loadObjectList();
// I'm not sure what this query is for, but since it probably isn't supposed to be limited to a set number of items, don't update it's setQuery call.
$sql2 = "SELECT * FROM #__user_usergroup_map WHERE group_id = 5 or group_id = 8";
$db->setQuery($sql2);
$rows2 = $db->loadObjectList();
I think that fixes the problem that you are having.
That being said, you have a host of minor issues that are making this a lot harder for you or just using outdated practices:
$limitstart = JRequest::getVar('limitstart', 0, '', 'int');
Using JRequest::getVar() is deprecated and likely to be removed in future versions of Joomla. Instead use this:
$limitstart = JFactory::getApplication()->input->get('limitstart', 0, 'INT');
Note that the parameters have changed slightly. This uses a different class to parse input to the application.
$this->assignRef('rows',$rows);
The above is unnecessary anymore (was only needed back in PHP4 from what I understand). Instead just do $this->rows = $rows;
Finally, the big overall issue is that you aren't really using Joomla's help.
Your model should just be extending from the class JModelList since you are trying to create a list of events. If you extend from that class and name your functions properly, Joomla will do most of the work:
Rename _buildQuery to getListQuery.
Pretty much delete every other function in your model, since Joomla has all of them in JModelList doing basically the same things.
Update your view to this:
class EventViewListing extends JViewLegacy
{
// Overwriting JView display method
function display($tpl = null)
{
$JDoc = JFactory::getDocument();
$db = JFactory::getDBO();
$this->pagination = $this->get('Pagination');
$this->rows = $this->get('Items');
$sql2 = "SELECT * FROM #__user_usergroup_map WHERE group_id = 5 or group_id = 8";
$db->setQuery($sql2);
$this->rows2 = $db->loadObjectList();
// $JDoc->setTitle(' ');
// Display the view
parent::display($tpl);
}
}
$this->get() in the JViewLegacy class will call the model (with the same name as the view) and run the method of that model that starts with get followed by whatever word is in the function, so $this->get('Pagination') calls the models getPagination function.
And again, all of the functions that you are adding in the model exist already in libraries/legacy/model/list.php, so just use them!
Related
I am essentially creating a chunking function for a file export, and I have a select->from->where that I have built already. I want to be able to call 'get' twice each time with different limit/offset values.
Here's a walk-through of the basic idea.
// BallReport.php
function ProcessData(){
//Report 1
$query = createSelectQuery();
$query = applyReportOneWhereValues($query);
$results1 = CSVTool::processLargeDataSet($query, 10, 1000);
//Report 2
$query = createSelectQuery();
$query = applyReportTwoWhereValues($query);
$results2 = CSVTool::processLargeDataSet($query, 10, 1000);
}
function createSelectQuery(){
// the select is complicated having multiple joins and sub queries
// so I only want to have to write this once
$query = $this->db->select('ball.name,
color.name,
size.name,
shape.name')
->from('ball')
->join('color', 'ball.color_id = color.id')
->join('size', 'ball.size_id = size.id')
->join('shape', 'ball.shape_id = shape.id');
return $query;
}
function applyReportOneWhereValues($query){
// I have 2 different sets of where parameters
// But they are both using the same select
// so I separated them into these functions
// So I can apply the set of where statements
// all at once
$query = $query->where("table.color", "blue")
->where("table.size" , "large")
->where("table.shape", "round");
return $query;
}
function applyReportTwoWhereValues($query){
$query = $query->where("table.color", "red")
->where("table.size" , "small")
->where("table.shape", "round");
return $query;
}
//In CSVTool.php
public static function processLargeDataSet($query, $numberOfPages, $chunkSize){
// Since the data set is going to be so large we want to process in chunks
// So that we don't hit the limit and break mid way.
// To do that we only call the DB in sets of 1000 rows
for(int $i = 0; $i <= $numberOfPages: $i++){
processRows($query, $i * $chunkSize, $chunkSize);
}
}
function processRows($query, $offset, $limit){
// We limit in here so each time it's called we change the offset and limit
$query = $query->offset($offset)->limit($limit);
$valuesToProcess = $query->get()->result_array();
// process the rows here
}
this of course doesn't work because once processRows calls $query->get() the first time all subsequent calls throws a Query error: No tables used
Is there any solution for this? Is there a chunking function in Codeigniter 2 that I'm unaware of?
Here is a new answer to the revised question.
public function ProcessData()
{
//Report 1
$query_builder = $this->applyReportOneWhereValues($this->createSelectQuery());
$this->db->stop_cache();
$results1 = CSVTool::processLargeDataSet($query_builder, 10, 1000);
$this->db->flush_cache();
//Report 2
$query_builder = $this->applyReportTwoWhereValues($this->createSelectQuery());
$this->db->stop_cache();
$results2 = CSVTool::processLargeDataSet($query_builder, 10, 1000);
$this->db->flush_cache(); //just to be safe
}
public function createSelectQuery()
{
$this->db->start_cache();
return $this->db->select('ball.name, color.name, size.name, shape.name')
->join('color', 'ball.color_id = color.id')
->join('size', 'ball.size_id = size.id')
->join('shape', 'ball.shape_id = shape.id');
}
public function applyReportOneWhereValues($query_builder)
{
return $query_builder
->where("table.color", "blue")
->where("table.size", "large")
->where("table.shape", "round");
}
public function applyReportTwoWhereValues($query_builder)
{
return $query_builder
->where("table.color", "red")
->where("table.size", "small")
->where("table.shape", "round");
}
In CSVTool.php
/**
* Process the records in chunks
* #param CI_DB_query_builder $qb An instance of the CI_DB_query_builder class
* #param int $numberOfPages The number of pages to create in the set (1 to n)
* #param int $pageSize The number of records per page
*/
public static function processLargeDataSet($qb, $numberOfPages, $pageSize)
{
if($numberOfPages < 1)
{
$numberOfPages = 1;
}
for($i = 1; $i < $numberOfPages; $i++)
{
$valuesToProcess = $qb
->get('ball', $pageSize, $i - 1 * $pageSize)
->result_array();
// process the rows in $valuesToProcess
}
}
I think what you are looking for is "Active Record Caching". This could be managed from a couple different places. In this answer it is in ProcessData()
Note:
You were assigning lots of things to the same var $query and passing it around a lot for no good reason I can see. And you are often overwriting $query with the exact same value multiple times in a row. I have used $this->db in most of the places you used $query.
public function ProcessData()
{
//Report 1
$this->db->start_cache();
//createSelectQuery(); not needed if you want all fields from one table
applyReportOneWhereValues();
$this->db->stop_cache();
processLargeDataSet(10, 1000);
//Report 2
$this->db->flush_cache()
$this->db->start_cache();
//createSelectQuery(); not needed if you want all fields from one table
applyReportTwoWhereValues();
$this->db->stop_cache();
processLargeDataSet(10, 1000);
$this->db->flush_cache();
}
Your question uses select("*") and from("table_name") which can be eliminated if you really want all fields from one table. When get("table_name") is used and there is no select() call then all fields are assumed. IOW, the query statement would be SELECT * FROM 'table_name';
Based on the question's code it seems you don't need the createSelectQuery() function.
Your "apply where" functions but re-written using method chaining.
public function applyReportOneWhereValues()
{
$this->db
->where("table.color", "blue")
->where("table.size", "large")
->where("table.shape", "round");
}
public function applyReportTwoWhereValues()
{
$this->db
->where("table.color", "red")
->where("table.size", "small")
->where("table.shape", "round");
}
I have eliminated processRows() and incorporated that logic into processLargeDataSet(). Notice how get() is used - passing a table name, limit, and offset - to remove the need for select(), from(), limit(), and offset() calls.
/**
* Process the records in chunks
* #param int $numberOfPages The number of pages to create in the set (1 to n)
* #param int $pageSize The number of records per page
*/
function processLargeDataSet($numberOfPages, $pageSize)
{
if($numberOfPages < 1)
{
$numberOfPages = 1;
}
for($i = 1; $i < $numberOfPages; $i++)
{
$valuesToProcess = $this->db
->get('table', $pageSize, ($i-1) * $pageSize)
->result_array();
// process the rows in $valuesToProcess
}
}
I have been pulling my hair out for too long looking at this error. I am using Codeigniter 2 and have created MY_Controller class to load a few settings into my session data.
Which you can see below:
class MY_Controller extends CI_Controller {
protected $ajax = 0;
public function __construct() {
parent::__construct();
$this->load->model('settings_model');
//is the session user agent set
if ($this->session->userdata('browser') == false)
{
$this->load->library('user_agent');
$this->session->set_userdata(array(
'browser' => $this->agent->browser(),
'browser_version' => $this->agent->version(),
'is_mobile' => $this->agent->is_mobile() ? 1 : 0
));
}
//is the settings loaded
if ($this->session->userdata('league_name') == false)
{
$this->Settings_model->get_general_settings();
}
//get the menu if we need to
//if ($this->session->userdata('menu') == false)
//$this->Settings_model->get_menu_items();
//set the main part of the title
$this->set_title($this->session->userdata('league_name'));
//get that referring url
$this->session->set_userdata('refered_from', isset($_SERVER['HTTP_REFERER']) ? $_SERVER['HTTP_REFERER'] : base_url());
//ajax request
$this->ajax = isset($_GET['ajax']) ? 1 : 0;
}
}
Where I am running into the problem is I keep getting this error:
Fatal error: Call to a member function get_general_settings() on a non-object in C:\xampp\htdocs\osmdev\application\controllers\welcome.php on line 12
Here is the Settings_model.php file that I am loading, yes it is in my application/models folder:
class Settings_model extends CI_Model
{
// Call the Model constructor
function __construct() {
parent::__construct();
}
//get the general settings
function get_general_settings() {
$query = "SELECT setting_id, variable, value FROM settings WHERE non_session = 0";
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$this->session->set_userdata($row['variable'], stripslashes($row['value']));
}
//get all the settings we have
function get_all_settings() {
$query = "SELECT setting_id, variable, value FROM settings";
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$this->session->set_userdata($row['variable'], stripslashes($row['value']));
}
//get a specfic setting variable
function get_specific_setting($var) {
$query = "SELECT setting_id, variable, value FROM settings WHERE variable = '".$var;
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$this->session->set_userdata($row['variable'], stripslashes($row['value']));
}
//get a specific type of setting
function get_type_setting($type) {
$query = "SELECT setting_id, variable, value FROM settings WHERE action = '".$type;
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$this->session->set_userdata($row['variable'], stripslashes($row['value']));
}
//get all the menu items
function get_menu_items($type=0) {
$query = "SELECT menu_id, title, menu_url, parent_id, level, function_used, perm_id, icon FROM menu WHERE active = 1 AND is_admin_menu = '".$type;
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$items[$row['menu_id']] = $row;
$this->session->set_userdata('menu', $items);
}
}
I am trying to call the get_general_settings function. Can anyone see what I am doing wrong?
You could try to setup the model to store $row into an array and then return the array.
Your model:
function get_general_settings() {
$rows = array();
$query = "SELECT setting_id, variable, value FROM settings WHERE non_session = 0";
$result = $this->db->query($query);
foreach ($result->result_array() as $row)
$variable = $row['variable'];
$value = stripslashes($row['value']);
$rows[] = $variable[$value];
return $rows[]
Your controller:
//is the settings loaded
if ($this->session->userdata('league_name') == false)
{
//set userdata to returned $rows[]
$this->session->set_userdata($this->Settings_model->get_general_settings());
}
//echo last_query to test in mysql
$this->db->last_query();
See if that will help solve your problem. I would print_r($this->Settings_model->get_general_settings()); just to see if anything was placed in the array.
Then if nothing is there, echo the last_query to see what it's asking MySQL for and then run that returned query in mysql and see if you get at least one row.
This error can happen when your database user doesn't have select permission for the table you're trying to query. It doesn't make sense, but it happens from time to time.
I developed my own joomla 2.5 custom component for displaying data table in front-end.It contain filtering,paging and sorting.When navigate via paging it always shows only first 20.
Is there any way to override limit of a query which generate on function getListQuery().
My populateState method is
protected function populateState($ordering = null, $direction = null) {
// Initialise variables.
$app = JFactory::getApplication();
$search = $this->getUserStateFromRequest($this->context . '.filter.search', 'filter_search');
$filter_order = $this->getUserStateFromRequest($this->context . '.filter_order', 'filter_order');
//$filter_order = JRequest::getCmd('filter_order');
$filter_order_Dir = $this->getUserStateFromRequest($this->context . '.filter_order_Dir', 'filter_order_Dir');
//$filter_order_Dir = JRequest::getCmd('filter_order_Dir');
'filter_region', '');
$this->setState('filter_order', $filter_order);
$this->setState('filter_order_Dir', $filter_order_Dir);
// List state information
$limit = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'));
$this->setState('list.limit', $limit);
$limitstart = JRequest::getVar('limitstart', 0, '', 'int');
$this->setState('list.start', $limitstart);
parent::populateState();
}
Constructor method is
function __construct() {
parent::__construct();
//Get configuration
$app = JFactory::getApplication();
$config = JFactory::getConfig();
// Get the pagination request variables
$this->setState('limit', $app->getUserStateFromRequest('com_jointcm.limit', 'limit', $config->getValue('config.list_limit'), 'int'));
$this->setState('limitstart', JRequest::getVar('limitstart', 0, '', 'int'));
}
List query method is
protected function getListQuery() {
// Create a new query object.
$db = JFactory::getDBO();
$query = $db->getQuery(true);
//code goes here...
..............
return $query;
}
After some digging around and taking a look at the source code of the JModelList class, I realized that problem is with
\libraries\joomla\application\component\modellist.php file ,method name public function getItems(),line number 115.
I changed it to
public function getItems()
{
// Get a storage key.
$store = $this->getStoreId();
// Try to load the data from internal storage.
if (isset($this->cache[$store]))
{
return $this->cache[$store];
}
// Load the list items.
$query = $this->_getListQuery();
//$items = $this->_getList($query, $this->getStart(), $this->getState('list.limit'));
$items = $this->_getList($query, $this->getState('limitstart'), $this->getState('list.limit'));
// Check for a database error.
if ($this->_db->getErrorNum())
{
$this->setError($this->_db->getErrorMsg());
return false;
}
// Add the items to the internal cache.
$this->cache[$store] = $items;
return $this->cache[$store];
}
Change was
$items = $this->_getList($query, $this->getStart(), $this->getState('list.limit'));
to
$items = $this->_getList($query, $this->getState('limitstart'), $this->getState('list.limit'));
It works fine.
In JModelList's getItems() the default method uses getStart() which in turn uses your models getQuery() to get a count of the number of items returned by your query, via _getListCount($query) which in turn calls the particular database adaptors version of getNumRows()). That value is used in the calculation in getStart(), if you have a large complicated query and don't really need to use the fancy getStart() implementation you can just override it in your model (i.e. your version of the JModelList class)
e.g. for our components model's for the front end which have rather complicated $query's returned by getListQuery, in their most basic implementation they do something similar to this:
public function getStart()
{
return $this->getState('list.start');
}
If you don't override it the default JModelList getStart() is invoked which looks like this:
/**
* Method to get the starting number of items for the data set.
*
* #return integer The starting number of items available in the data set.
*
* #since 11.1
*/
public function getStart()
{
$store = $this->getStoreId('getstart');
// Try to load the data from internal storage.
if (isset($this->cache[$store]))
{
return $this->cache[$store];
}
$start = $this->getState('list.start');
$limit = $this->getState('list.limit');
$total = $this->getTotal();
if ($start > $total - $limit)
{
$start = max(0, (int) (ceil($total / $limit) - 1) * $limit);
}
// Add the total to the internal cache.
$this->cache[$store] = $start;
return $this->cache[$store];
}
But, this probably isn't the problem area, it's more likely in your populateState(). At the end of populateState() you call parent::populateState() (if was called at the beginning it wouldn't be overwriting results of your method).
You seem to be duplicating the work done by the parent::populateState() which is probably redundant, looking at JModelList's implementation you will see this:
protected function populateState($ordering = null, $direction = null)
{
// If the context is set, assume that stateful lists are used.
if ($this->context)
{
$app = JFactory::getApplication();
$value = $app->getUserStateFromRequest('global.list.limit', 'limit', $app->getCfg('list_limit'), 'uint');
$limit = $value;
$this->setState('list.limit', $limit);
$value = $app->getUserStateFromRequest($this->context . '.limitstart', 'limitstart', 0);
$limitstart = ($limit != 0 ? (floor($value / $limit) * $limit) : 0);
$this->setState('list.start', $limitstart);
// Check if the ordering field is in the white list, otherwise use the incoming value.
$value = $app->getUserStateFromRequest($this->context . '.ordercol', 'filter_order', $ordering);
if (!in_array($value, $this->filter_fields))
{
$value = $ordering;
$app->setUserState($this->context . '.ordercol', $value);
}
$this->setState('list.ordering', $value);
// Check if the ordering direction is valid, otherwise use the incoming value.
$value = $app->getUserStateFromRequest($this->context . '.orderdirn', 'filter_order_Dir', $direction);
if (!in_array(strtoupper($value), array('ASC', 'DESC', '')))
{
$value = $direction;
$app->setUserState($this->context . '.orderdirn', $value);
}
$this->setState('list.direction', $value);
}
else
{
$this->setState('list.start', 0);
$this->state->set('list.limit', 0);
}
}
The most obvious condition in the parent::populateState() that causes list.start to be set to 0 is the very first line, which checks your object context value, it may be that something is going wrong there and your objects context value is equating to false. (I can't see context defined anywhere... so, it will try an guess/build a context value for you in __construct()).
However, it may also be in the way in which getUserSateFromRequest() is processing the values returned from your request, it's hard to tell with the code available.
You can add limit like this $query->limit('0,40'); in getListQuery() function
Do you have list_limit defined in your component options? If not, then add a new parameter to your component options and call it list_limit. This will allow you to set your pagination limit to what ever you want in the component options.
class Application_Model_DbTable_Email extends Zend_Db_Table_Abstract
{
protected $_name = 'memberdetail';
function getUserid($email)
{
$subquery = $this->select()
->from('memberdetail', array('memberid'))
->where('email = ?', $email);
$select = $this->select()
->from('usertable', array('userid'))
->join('memberdetail', 'usertable.userid = memberdetail.memberid')
->where('usertable.userid = ?', $subquery);
$row = $select->query()->fetch();
if (!$row) {
echo "User id not found";
} else {
return $userid = $row['userid'];
}
}
}
Hi, I am trying to return the userid from the above queries. However, the queries does not seemed to be executed as I always get refreshed whenever I call this function.
P.S this set of queries were given to me by another member.
it looks like this is being over thought. According to the info provided usertable.userid = memberdetail.memberid with this being the case your function is simple.
/** this function assumes one and only one email will match a memberid
* this function can be improved by validating $email as existing in DB
* prior to querying DB, should be done at form level but could be accomplished here
* with Zend_Validate_Db_RecordExists()
*/
public function getUserIdFromEmail($email) {
$select = $this->select();
$select->where('email = ?',$email);
$row = $this->fetchRow($select);//fetch a single row
if (!is_null($row) {//fetchRow returns null if no row matched
return $row->memeberid;//return memberid as string/integer = usertable.userid
} else {
//handle error
}
}
It would have been useful to tell people you are using Zend framework.
You need to establish a connection to the database for $this as described in steps 1 and 2 in this link:
http://framework.zend.com/manual/en/zend.db.select.html/
You can try this, if it helps:
function getUserid($email){
$select = $this->select()
->setIntegrityCheck(false)
->from(array('m' => 'memberdetail'), array('b.userid'))
->join(array('b' => 'usertable'), 'b.userid = m.memberid')
->where('m.email = ?', $email);
$row = $this->getAdapter()->fetchAll($select);
if (!$row) {
throw new Exception("User id not found");
} else {
return $row->toArray();
}
}
I have a simple recursive array function that looks like this:
function recursive_array($results) {
global $DBH;
if (count($results)) {
echo $res - > Fname;
foreach($results as $res) {
$STH = $DBH - > query("SELECT FID,FParentID,Fname FROM list WHERE FParentID = ".$res - > FID."");
$fquerycount = $STH - > rowCount();
$STH - > setFetchMode(PDO::FETCH_OBJ);
recursive_array($STH);
}
}
}
$FID = isset($_GET['FID']) ? $_GET[' FID'] : 0;
$STH = $DBH - > query("SELECT FID,FParentID,Fname FROM list WHERE FParentID ='0' ");
$STH - > setFetchMode(PDO::FETCH_OBJ);
recursive_array($STH);
I also have created a simple query class that looks like this:
class queryloop {
function __construct($args) {
global $DBH;
$table = $args['tbl'];
if (array_key_exists('orderby', $args)): $orderby = 'ORDER BY '.$args['orderby'];
else: $orderby = '';endif;
if (array_key_exists('groupby', $args)): $groupby = 'GROUP BY '.$args['groupby'];
else: $groupby = '';endif;
if (array_key_exists('start', $args)): unset($orderby);$start = $args['start'].' , ';
else: $start = '';endif;
if (array_key_exists('limit', $args)): $limit = 'LIMIT '.$start.' '.$args['limit'];
else: $limit = '';endif;
// UNSET the previously used array keys so they are not use again to create the query string
unset($args['tbl']);
unset($args['orderby']);
unset($args['groupby']);
unset($args['start']);
unset($args['limit']);
// Checks if args still an array after UNSET above. If not empty create the query string
if (!empty($args)): foreach($args as $k = > $v): $querystr. = 'AND '.$k.' = \''.$v.'\'';endforeach;
// If args array empty return empty query string
else: $querystr = '';endif;$STH = $DBH - > query("SELECT * FROM ".$table." WHERE key = '".KEY."' ".$querystr." ".$groupby." ".$orderby." ".$limit." ");
if ($STH): $STH - > setFetchMode(PDO::FETCH_OBJ);
while ($row = $STH - > fetch()): foreach($row as $key = > $val):
// check if value is numeric //
if (is_numeric($row - > $key)): $data[$row - > ID][$key] = $row - > $key;
// check if value is array //
elseif(is_array($row - > $key)): $data[$row - > ID][$key] = $row - > $key;
// check if value is not numeric or array convert to html entities //
else: $data[$row - > ID][$key] = htmlentities($row - > $key);endif;endforeach;endwhile;$this - > data = json_encode($data); // return json array if data
else: $this - > data = ''; // return 'null' if no data
endif;
}
}
$args = array('tbl' = > 'atable', 'limit' = > '5', 'start' = > '200', 'orderby' = > 'ID DESC');
$loop = new queryloop($args) // run the loop etc.
How do I turn my recursive array into something like the class queryloop so that I can "pull out" json endoded data I know that this (below) is totally wrong but what ever I do I cannot get a correctly formed json array or even anything to return form my attempted class below. Help would be much appreciate. Thanks in advance.
class recloop {
function __construct() {}
function recursive_array($results) {
global $DBH;
if (count($results)) {
foreach($results as $res) {
echo $res - > Name;
$STH = $DBH - > query("SELECT * FROM atable WHERE ParentID = ".$res - > ID."");
$fquerycount = $STH - > rowCount();
$STH - > setFetchMode(PDO::FETCH_OBJ);
recursive_array($STH);
}
}
}
function recursive_start() {
global $DBH;
$ID = isset($_GET['ID']) ? $_GET['ID'] : 0;
$STH = $DBH - > query("SELECT * FROM atable WHERE ParentID = '".$ID."' ");
$STH - > setFetchMode(PDO::FETCH_OBJ);
recursive_array($STH);
}
}
How do I turn my recursive array into something like the class queryloop so that I can "pull out" json endoded data I know that this (below) is totally wrong but what ever I do I cannot get a correctly formed json array or even anything to return form my attempted class below. Help would be much appreciate. Thanks in advance.
To answer your question, I would say it's not specific if you encapsulate your routines into objects or not that much, but that you take care that each object is there for a sole purpose. For example:
One object is fetching the data from the database.
One object/composite/array is the data-structure, representing the data.
One object or function is taking over the job to convert/encode the data into json.
Within your code I see that you right now are only running SQL-queries. The data fetched from the database server is not stored into a return variable at all, it get's directly consumed while being recursively processed. I assume you do this for debugging reasons.
So the actual question is, what do you want to do? You write that you want to encode an object into json output, which is perfectly possible with json_encodeDocs, however I think you refer to some specific data, like the entity (data) of the most parentId or something.
Following is some mock-up code based on your code for reading purposes (not tested, must not match your needs) that can provide all parent objects of that one specified by ID by using recursion. The recursion has been criticised because this can result in running a lot of queries - and additionally there is risk to create an endless loop which will result in a recursion stack overflow - your program crashes then.
To handle that alternatively, this is bound to the database design (which should be done before the design of the code, and I don't know your database design nor what you actually want to do, so I can't add assumptions for that). So the following code takes care of already queried objects only while still using recursion as the strategy to query your database.
For the actual data-structure I opted for an array of plain old PHP objects, keyed by the ID field from the database (which I assume that it exists per record):
/**
* HTTP Get Parameter (Input)
*/
class HTTPGetParameter {
private $name;
private $default;
public function __construct($name, $default = '') {
$this->name = (string) $name;
$this->default = (string) $default;
}
/**
* #return string
*/
public function getValue()
{
return isset($_GET[$name]) ? $_GET[$name] : $this->default;
}
/**
* #return int
*/
public function getValueInt()
{
return (int) $this->getValue();
}
/**
* #link http://www.php.net/manual/en/language.oop5.magic.php#language.oop5.magic.tostring
*/
public function __toString()
{
return $this->getValue();
}
}
/**
* Data Provider
*/
class PDODataProvider
{
private $pdo;
public function __construct(PDO $pdo)
{
$this->pdo = $pdo;
}
/**
* #return array
*/
public function findAllATableParents($id)
{
return $this->findAllOn('atable', 'ParentID', $id);
}
public function findAllBTableParents($id)
{
return $this->findAllOn('btable', 'ParentID', $id);
}
private function findAllOn($table, $field, $id)
{
$id = (int) $id;
$objects = array();
$sql = sprintf("SELECT * FROM %s WHERE %s = '%d'", $table, $field, $id);
$pdoStatement = $this->pdo->query($sql);
$pdoStatement->setFetchMode(PDO::FETCH_OBJ);
foreach($pdoStatement as $parent)
{
$parentId = $parent->ID;
# parents that had been queried are skipped
if (isset($objects[$parentId]))
continue;
$objects[$parentId] = $parent;
# add parent objects by recursion
$objects += $this->findAllParents($parentId);
}
return $objects;
}
}
/**
* main
*/
$data = new PDODataProvider($DBH);
$id = new HTTPGetParameter('ID', 0);
$objects = $data->findAllParents($id->getValueInt());
echo json_encode($objects);
I hope this example is helpful for you to answer your question.