Zend DB: null values - php

I would appreciate it if some one could explain why this query is returning null values. This query works fine when I use the fetchRow() method.
public function getCustomerRowWithAddress($customer_id)
{
$select = $this->select()->setIntegrityCheck(false);
$select->from('irh_TV.irh_site_location AS SL', array('name as location_name', 'start_date', 'end_date', 'service_pack_id', 'stb_id'));
$select->joinLeft('irh_TV.irh_customers AS C', 'C.customer_id = SL.customer_id AND C.active = 1 AND C.site_id = SL.site_id',
array('customer_id','surname', 'title', 'site_id', 'first_name', 'company', 'business_no', 'home_no', 'mobile_no', 'email', 'address_id'));
$select->joinLeft('irh_TV.tv_stb_data AS TV', 'TV.site_id = SL.site_id AND SL.stb_id = TV.id', array('user_id as mac_address'));
$select->joinLeft('irh_TV.irh_address AS AD', 'C.address_id = AD.id', array('address_line1', 'address_line2', 'town', 'county', 'country', 'postcode'));
$select->where("SL.customer_id = $customer_id");
//if($_REQUEST['d'] == 1) { echo $select; }
_syslog($select);
//$_rows = $this->fetchRow($select);
$_rows = $this->fetchAll($select);
return $_rows;
}
EDIT:
I try to access the rowset like so:
$model = _getModel();
$table = $model->getTable("irh_customers");
$customer_address_row = $table->getCustomerRowWithAddress($id);
//$customer_address_row = $table->getCustomerRowsWithAddress($id);
//$this->_row = $customer_address_row ? $customer_address_row : $table->getRowById($id);
$row_count = count($customer_address_row);
if($row_count > 0){
///$rows = $this->_row->toArray();
$this->exists = true;
$this->id = $id;
if($row_count > 1){
//$array = $customer_address_row->toArray();
foreach($customer_address_row->toArray() as $row){
foreach($row as $k => $v){
//if($k != 'stb_id' || $k != 'mac_address'){
if(!isset($this->k[$k])){
$this->k[$k] = $v;
}
/*}else if($k == 'stb_id'){
$this->k['stb_id'][] = $v;
}
else if($k == 'mac_address'){
$this->k['mac_address'][] = $v;
}*/
}
}
}else{
foreach($customer_address_row->toArray() as $k => $v)
{
_syslog($v);
$this->k[$k] = $v;
}
}
}

fetchRow() returns an object of Zend_Db_Table_Row_Abstract. fetchAll() returns an array.

The Zend_Db_Table_Rowset_Abstract class toArray method, behaves in wierd manner that is not documented. If you haven't iterated through the rows before calling it, it won't behave like expected.
So the solution would be to directly iterate thought the rowset (It can be iterated):
foreach ($customer_address_row as $row) {
//Do whatever you need with the row here
}
Hope this helps.

I've fixed it guys. Just had to check for an array first and get rid of the second row count check and its else statement.
if($row_count > 0){
$rows = $this->_row->toArray();
$this->exists = true;
$this->id = $id;
if(is_array($rows[0]) && isset($rows)){
foreach($rows as $i => $row){
foreach($row as $k => $v){
//Whatever
}
}
}

Related

php update to mysql with array not updating

I have a function that should be updating a row, no errors what so ever in the logs. From what I see it should be working. I took the function from a update user function and tried to mimic it for the new feature.
Here is the data array posting to it.
$data = array('id' => $vid, 'name' => $vname, 'logo' => $vlogo, 'info' => $vinfo, 'site' => $vsite, 'est' => $vest);
The post works, I am doing a dump on the updatecompany page. So they do get set. I think it may be with the function. Any insight would be wonderful!
public static function updateCompany($toUpdate = array(), $company = null){
self::construct();
if( is_array($toUpdate) && !isset($toUpdate['id']) ){
if($company == null){
echo "No company ID set!";
}
$columns = "";
foreach($toUpdate as $k => $v){
$columns .= "`$k` = :$k, ";
}
$sql = self::$dbh->prepare("UPDATE companys SET {$columns} WHERE `id` = :id");
$sql->bindValue(":id", $company);
foreach($toUpdate as $key => $value){
$value = htmlspecialchars($value);
$sql->bindValue(":$key", $value);
}
$sql->execute();
}else{
return false;
}
}
$vid = $_POST["idnum"];
$vname = $_POST["name"];
$vlogo = $_POST["logo"];
$vinfo = $_POST["info"];
$vsite = $_POST["site"];
$vest = $_POST["est"];
I would maybe try using the bind array into your execute() method since you are just binding the values (I assume this is PDO). Another feature is to use an array to assemble the column portions and implode at the time of use.
public static function updateCompany($toUpdate = array(), $company = null)
{
# Also this may supposed to be: self::__construct(); ?? Notice the "__" before "construct"
self::construct();
if(is_array($toUpdate) && !isset($toUpdate['id'])) {
if(empty($company)){
# Throw exception, catch it in a parent wrapper
throw new \Exception("No company ID set!");
# Stop, no sense in continuing if an important part is missing
return;
}
foreach($toUpdate as $k => $v){
$bKey = ":{$k}";
# I would create a bind array here
$bind[$bKey] = $value;
# I generally save to an array here to implode later
$columns[] = "`{$k}` = {$bKey}";
}
# Add the id here
$bind[":id"] = $company;
# I would use a try here for troubleshooting PDO errors
try {
# Create sql with imploded columns
$sql = self::$dbh->prepare("UPDATE companys SET ".implode(",",$columns)." WHERE `id` = :id");
# Throw the bind array into the execute here
$sql->execute($bind);
}
catch(\PDOException $e) {
# I would only die here to see if there are any errors for troubleshooting purposes
die($e->getMessage());
}
} else {
return false;
}
}
Your update SQL could not work because you have comma in update value set.
See, you attached comma without any consideration:
$columns = "";
foreach($toUpdate as $k => $v){
$columns .= "`$k` = :$k, ";
}
Then the final SQL will look something like this:
UPDATE companys SET `name`=:name, `logo`=:logo, WHERE `id`=:id
Do you notice the comma just before WHERE? it should not be there!
So you should update the code like following:
$columns = "";
foreach($toUpdate as $k => $v){
if ($columns != "") $columns .= ",";
$columns .= "`$k` = :$k ";
}
This should be working.
or to no need to be aware of last comma try this:
$columns = array();
foreach($toUpdate as $k => $v){
$columns[] = "`$k` = :$k";
}
$sql = self::$dbh->prepare("UPDATE `companys` SET ".implode(',', $columns)." WHERE `id` = :id");

Reduce amount of queries and increase performance for categories and subcategories queries

EDIT 3: Got it down to 300-500 ms by changing flatten method to only merge arrays if not empty.
EDIT 2: Got it down to 1.6 seconds by only calling array_replace for non empty array. Now all that is left to do is optimize the function sort_categories_and_sub_categories. That is NOW the bottleneck. If I remove that I am down to 300ms. Any ideas?
get_all_categories_and_sub_categories
foreach(array_keys($categories) as $id)
{
$subcategories = $this->get_all_categories_and_sub_categories($id, $depth + 1);
if (!empty($subcategories))
{
$categories = array_replace($categories, $subcategories);
}
}
EDIT
I improved performance by over 50% (6 seconds --> 2.5 seconds) by doing a cache in the get_all method. It reduces the amount of queries to 1 from 3000. I am still wondering why it is slow.
I have the following method for getting categories and nested sub categories. If a user has a couple hundred (or thousand) top level categories it does a bunch of queries for each category to find the children. In one case I have 3000 categories and it did 3000 queries. Is there a way to optimize this to do less queries? OR should I just check to see if they have a lot of categories NOT to try to show nested too.
function get_all_categories_and_sub_categories($parent_id = NULL, $depth = 0)
{
$categories = $this->get_all($parent_id);
if (!empty($categories))
{
foreach($categories as $id => $value)
{
$categories[$id]['depth'] = $depth;
}
foreach(array_keys($categories) as $id)
{
$categories = array_replace($categories, $this->get_all_categories_and_sub_categories($id, $depth + 1));
}
return $categories;
}
else
{
return $categories;
}
}
function get_all($parent_id = NULL, $limit=10000, $offset=0,$col='name',$order='asc')
{
static $cache = array();
if (!$cache)
{
$this->db->from('categories');
$this->db->where('deleted',0);
if (!$this->config->item('speed_up_search_queries'))
{
$this->db->order_by($col, $order);
}
$this->db->limit($limit);
$this->db->offset($offset);
foreach($this->db->get()->result_array() as $result)
{
$cache[$result['parent_id'] ? $result['parent_id'] : 0][] = array('name' => $result['name'], 'parent_id' => $result['parent_id'], 'id' => $result['id']);
}
}
$return = array();
$key = $parent_id == NULL ? 0 : $parent_id;
if (isset($cache[$key]))
{
foreach($cache[$key] as $row)
{
$return[$row['id']] = array('name' => $row['name'], 'parent_id' => $row['parent_id']);
}
return $return;
}
return $return;
}
function sort_categories_and_sub_categories($categories)
{
$objects = array();
// turn to array of objects to make sure our elements are passed by reference
foreach ($categories as $k => $v)
{
$node = new StdClass();
$node->id = $k;
$node->parent_id = $v['parent_id'];
$node->name = $v['name'];
$node->depth = $v['depth'];
$node->children = array();
$objects[$k] = $node;
}
// list dependencies parent -> children
foreach ($objects as $node)
{
$parent_id = $node->parent_id;
if ($parent_id !== null)
{
$objects[$parent_id]->children[] = $node;
}
}
// clean the object list to make kind of a tree (we keep only root elements)
$sorted = array_filter($objects, array('Category','_filter_to_root'));
// flatten recursively
$categories = self::_flatten($sorted);
$return = array();
foreach($categories as $category)
{
$return[$category->id] = array('depth' => $category->depth, 'name' => $category->name, 'parent_id' => $category->parent_id);
}
return $return;
}
static function _filter_to_root($node)
{
return $node->depth === 0;
}
static function _flatten($elements)
{
$result = array();
foreach ($elements as $element)
{
if (property_exists($element, 'children'))
{
$children = $element->children;
unset($element->children);
}
else
{
$children = null;
}
$result[] = $element;
if (isset($children))
{
$flatened = self::_flatten($children);
if (!empty($flatened))
{
$result = array_merge($result, $flatened);
}
}
}
return $result;
}

PHP MYSQL - Filter and sort function

I m working on a filter and sort option for a website and seem to be stuck. The whole code can be seen here: http://pastebin.com/pYfnLiSZ
It's not 100% complete ... parts like this
if(array_key_exists('number', $sorts))
{
$issue = $sorts['number'];
$setIssue = "AND i.item_number = ?";
}
still need to be edited a bit, but I hope it's understandable.
The part that I can't figure out is this(line 126 in pastebin):
if( !empty($userIDS) && $letter )
{
$ref = array();
foreach($userIDS as $id)
{
$ref[] = $id['followed'];
}
$ref[] = $letter;
$params = implode(",", array_fill(0, count($userIDS), "?"))."?";
$prep = implode("", array_fill(0, count($userIDS), "i"))."s";
}
I'm not sure how to make the above if dynamic. I only need it if $userIDS array is not empty and either $letter or $year or $publisher or $number are set. So it can basically be any combination. Items belonging to the users in the $userIDS array and filtered by letter, year, publisher, number and maybe in the future other filters. Or it can be year and publisher, or publisher, number and year ... and so on.
Since you are trying to "Combination of the constraints or conditions", I can suggest you the below pattern that i've used for shops:
define a class
make rules
get query
optimize for cache or other things
class condition {
public function add($query) {
$this->query[] = $query;
return $this;
}
public function get() {
return " SELECT * FROM TABLE WHERE " . implode(" and " ,$this->query);
}
$con = new condition();
$query = $con->add("price > 100 and price < 200")->add("year > 1980")->get();
I use something similar to this at work, but obviously not as thrown together:
$search = [
'fields' => [
'name',
'phone',
'email'
],
'filter' => [
'name LIKE' => 'Joe'
]
];
function search(array $search) {
$allowedFields = [
'name',
'phone',
'email',
'address',
];
$allowedFilters = [
'name',
'phone',
'email',
];
$allowedActions = [
'=',
'LIKE',
'<',
'<=',
'>',
'>=',
];
$fields = array();
if(isset($search['fields'])) {
foreach($search['fields'] as $field) {
if(in_array($field, $allowedFields)) $fields[] = $field;
}
} else {
$fields = $allowedFields;
}
$filters = array();
if(isset($search['filters'])) {
foreach($search['filters'] as $filter => $val) {
$filter_split = explode(' ', $filter);
$field = $filter;
$action = '=';
if(count($filter_split) > 1) {
$field = $filter_split[0];
$action = $filter_split[1];
}
if(!in_array($action, $allowedActions)) continue;
if(in_array($field, $allowedFilters)) $filters[] = "{$field} {$action} {$val}";
}
}
$fields_str = implode(',', $fields);
$query = "SELECT {$fields_str} FROM users "
if(count($filters) > 0) {
$first = true;
foreach($filters as $filter) {
$action = 'AND';
if($first) {
$action = 'WHERE';
$first = false;
}
$query .= "{$action} {$filter} ";
}
}
mysqli_query($db, $query);
}

Split an array into sub arrays

I would like to split an array:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
based on the color attribute of each item, and fill corresponding sub arrays
$a = array("green", "yellow", "blue");
function isGreen($var){
return($var->color == "green");
}
$greens = array_filter($o, "isGreen");
$yellows = array_filter($o, "isYellow");
// and all possible categories in $a..
my $a has a length > 20, and could increase more, so I need a general way instead of writing functions by hand
There doesn't seem to exist a function array_split to generate all filtered arrays
or else I need a sort of lambda function maybe
You could do something like:
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = array_filter($o, function($item) {
if ($item->color == 'green') {
return true;
}
return false;
});
Or if you want to create something really generic you could do something like the following:
function filterArray($array, $type, $value)
{
$result = array();
foreach($array as $item) {
if ($item->{$type} == $value) {
$result[] = $item;
}
}
return $result;
}
$o = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$greens = filterArray($o, 'color', 'green');
$yellows = filterArray($o, 'color', 'yellow');
In my second example you could just pass the array and tell the function what to filter (e.g. color or some other future property) on based on what value.
Note that I have not done any error checking whether properties really exist
I would not go down the road of creating a ton of functions, manually or dynamically.
Here's my idea, and the design could be modified so filters are chainable:
<?php
class ItemsFilter
{
protected $items = array();
public function __construct($items) {
$this->items = $items;
}
public function byColor($color)
{
$items = array();
foreach ($this->items as $item) {
// I don't like this: I would prefer each item was an object and had getColor()
if (empty($item->color) || $item->color != $color)
continue;
$items[] = $item;
}
return $items;
}
}
$items = json_decode('[{"id":"1","color":"green"},{"id":"2","color":"green"},{"id":"3","color":"yellow"},{"id":"4","color":"green"}]');
$filter = new ItemsFilter($items);
$greens = $filter->byColor('green');
echo '<pre>';
print_r($greens);
echo '</pre>';
If you need more arguments you could use this function:
function splitArray($array, $params) {
$result = array();
foreach ($array as $item) {
$status = true;
foreach ($params as $key => $value) {
if ($item[$key] != $value) {
$status = false;
continue;
}
}
if ($status == true) {
$result[] = $item;
}
}
return $result;
}
$greensAndID1 = splitArray($o, array('color' => 'green', 'id' => 1));

Only showing last item in array

I'm trying to figure out why its only showing the last child_links in the roster, events, and social objects. I've included the site that has the print_r of the array function. Any help would be appreciated.
http://kansasoutlawwrestling.com/
function getSubMenuPages()
{
$this->db->select('id');
$this->db->where('short_name', 'mainnav');
$query = $this->db->get('site_menu_structures');
$menu_id = $query->row()->id;
$this->db->select('id, short_name, is_category');
$this->db->where('menu_structure_id', $menu_id);
$query = $this->db->get('site_menu_structures_links');
if ($query->num_rows() > 0)
{
$linksArray = $query->result();
echo "<pre>";
print_r( $linksArray );
echo "</pre>";
foreach ($linksArray as $key => $link)
{
if ($link->is_category == 'Yes')
{
$this->db->select('link_name, site_content_pages_id, link_url');
$this->db->where('site_menu_structures_links_id', $link->id);
$query = $this->db->get('site_menu_structures_links_children');
if ($query->num_rows() > 0)
{
foreach ($query->result() as $row)
{
$site_content_page_id = $row->site_content_pages_id;
$linksArray[$key]->child_links = array();
if ($site_content_page_id != 0)
{
$this->db->select('content_page_name, permalink');
$this->db->where('id', $site_content_page_id);
$query = $this->db->get('site_content_pages');
if ($query->num_rows() > 0)
{
$row = $query->row();
$linksArray[$key]->child_links = array(
'link_name' => $row->content_page_name,
'link_url' => $row->permalink
);
}
}
else
{
$linksArray[$key]->child_links = array(
'link_name' => $row->link_name,
'link_url' => $row->link_url
);
}
}
}
}
}
}
return $linksArray;
}
When you loop here:
foreach ($query->result() as $row)
{
$site_content_page_id = $row->site_content_pages_id;
$linksArray[$key]->child_links = array();
if ($site_content_page_id != 0)
{
you're inside another loop, so at each passage of this loop here the $key remains the same.
So, 1st external loop, ex. $key = 'key1'; I'll use some pseudo code to give the idea:
foreach results as row:
(loop nr 1):
linksarray['key1'] = empty array.
linksarray['key1'] = value;
(loop nr 2):
linksarray['key1'] = empty array
linksarray['key1'] = value2
endforeach;
2nd external loop, $Key = 'key2'
foreach results as row:
(loop nr 1):
linksarray['key2'] = empty array.
linksarray['key2'] = value;
(loop nr 2):
linksarray['key2'] = empty array
linksarray['key2'] = value2
endforeach;
I might have mis-looked something in all those loops, it's evening here and I'm a bit tired :)
Oh, and a piece of advice: your code gets easily a bit difficult to read; a small improvement would be to omit the table name (as it's not necessary), especially when it's so long; moreover, in AR you can omit the "from" clause and also chain method.
So, for ex., this:
$this->db->select('site_menu_structures_links_children.link_name, site_menu_structures_links_children.site_content_pages_id, site_menu_structures_links_children.link_url');
$this->db->from('site_menu_structures_links_children');
$this->db->where('site_menu_structures_links_children.site_menu_structures_links_id', $link->id);
$query = $this->db->get();
Could be easily rewritten as:
$query = $this->db->select('link_name,site_content_pages_id,link_url')
->where('site_menu_structures_links_id',$link->id)
->get('site_menu_structures_links_children');
Doing this might help you in identifying out the general code flow, spotting out the various runs
UPDATE
Try this
function getSubMenuPages()
{
$this->db->select('id');
$this->db->where('short_name', 'mainnav');
$query = $this->db->get('site_menu_structures');
$menu_id = $query->row()->id;
$this->db->select('id, short_name, is_category');
$this->db->where('menu_structure_id', $menu_id);
$query2 = $this->db->get('site_menu_structures_links');
if ($query2->num_rows() > 0)
{
$linksArray = $query2->result();
echo "<pre>";
print_r( $linksArray );
echo "</pre>";
foreach ($linksArray as $key => $link)
{
if ($link->is_category == 'Yes')
{
$this->db->select('link_name, site_content_pages_id, link_url');
$this->db->where('site_menu_structures_links_id', $link->id);
$query3 = $this->db->get('site_menu_structures_links_children');
if ($query3->num_rows() > 0)
{
$linksArray[$key]->child_links = array();
foreach ($query3->result() as $row)
{
$site_content_page_id = $row->site_content_pages_id;
//$linksArray[$key]->child_links = array();
if ($site_content_page_id != 0)
{
$this->db->select('content_page_name, permalink');
$this->db->where('id', $site_content_page_id);
$query4 = $this->db->get('site_content_pages');
if ($query4->num_rows() > 0)
{
$row = $query4->row();
$linksArray[$key]->child_links[]['link_name'] = $row->content_page_name;
$linksArray[$key]->child_links[]['link_url'] = $row->permalink;
}
}
else
{
$linksArray[$key]->child_links[]['link_name'] = $row->link_name;
$linksArray[$key]->child_links[]['link_url'] = $row->link_url;
}
}
}
}
}
}
return $linksArray;
}
basically, I moved the property assigment $linksArray[$key]->child_links = array(); outside the loop. Being followed by another loop, which can possibly have more values, I've created an index for each loop:
$linksArray[$key]->child_links[]['link_name'] = $row->content_page_name;
$linksArray[$key]->child_links[]['link_url'] = $row->permalink;
Try replacing this block of code:
$this->db->select('link_name, site_content_pages_id, link_url');
$this->db->where('site_menu_structures_links_id', $link->id);
$query = $this->db->get('site_menu_structures_links_children');
if ($query->num_rows() > 0)
{
$linksArray[$key]->child_links = array();
foreach ($query->result() as $row)
{
$site_content_page_id = $row->site_content_pages_id;
if ($site_content_page_id != 0)
{
$this->db->select('content_page_name, permalink');
$this->db->where('id', $site_content_page_id);
$query2 = $this->db->get('site_content_pages');
if ($query2->num_rows() > 0)
{
$row2 = $query2->row();
array_push($linksArray[$key]->child_links, array(
'link_name' => $row2->content_page_name,
'link_url' => $row2->permalink
));
}
}
else
{
array_push($linksArray[$key]->child_links, array(
'link_name' => $row->link_name,
'link_url' => $row->link_url
));
}
}
}

Categories