I have a PHP class that is meant to get a mysqli query, make a multidimensional array, and currently just echo the whole array. It is this code:
include("connect.php");
class database
{
public $motto;
public $motto_array = array();
public $rating;
public $rating_array = array();
public $category;
public $score;
private $mysqli;
public $counter_array = array();
public $multi_dim_values = array();
public $multi_dim_category = array();
function setMysqli($mysqli)
{
$this->mysqli = $mysqli;
}
function setCategory($category)
{
$this->category = $category;
}
function query_category()
{
if ($stmt = $this->mysqli->prepare("SELECT motto, score FROM mottos WHERE category=? ORDER BY score DESC"))
{
$stmt->bind_param("s", $this->category);
$stmt->execute();
$stmt->bind_result($motto, $ranking);
while ( $stmt->fetch() ) {
$this->motto_array[] = $motto;
$this->rating_array[] = $ranking;
}
$stmt->close();
}
}
function multi_dim_array()
{
$multi_dim_values = array($this->motto_array, $this->rating_array);
$counter_array = range(0,count($this->motto_array)-1);
foreach($counter_array as $index => $key) {
$foreach_array = array();
foreach($multi_dim_values as $value) {
$foreach_array[] = $value[$index];
}
$multi_dim_category[$key] = $foreach_array;
}
return $multi_dim_category;
}
}
$class = new database;
$class->SetMysqli($mysqli);
$class->SetCategory("person");
$class->query_category();
print_r($class->multi_dim_array);
print_r($class->multi_dim_category);
connect.php has the database connection information for the mysqli.
I am learning OOP, so I did this in procedural, and it works fine, with this code:
include("connect.php");
function category($mysqli, $cat)
{
if ($stmt = $mysqli->prepare("SELECT motto, score FROM mottos WHERE category=? ORDER BY score DESC"))
{
$stmt->bind_param("s", $cat);
$stmt->execute();
while($stmt->fetch())
{
printf ("[%s (%s) in %s] \n", $motto, $ranking, $category);
$array .= compact("motto", "category", "ranking");
}
print_r($array);*/
$a = array();
$b = array();
$c = array();
$stmt->bind_result($motto, $ranking);
while ( $stmt->fetch() ) {
$a[] = $motto;
$b[] = $ranking;
}
$result = array();
$values = array($a, $b);
$c = range(0,count($a)-1);
foreach($c as $index => $key) {
$t = array();
foreach($values as $value) {
$t[] = $value[$index];
}
$result[$key] = $t;
}
return $result;
$stmt->close();
}
}
$cat = "person";
$array_one = category($mysqli, $cat);
print_r($array_one);
This prints the multidimensional array just like I want it to.
What am I doing wrong in the OOP code?
Thank you.
Your code:
print_r($class->multi_dim_array);
You forgot the (), so you're not invoking the method. You're accessing a (non-existent) property. Try this:
print_r($class->multi_dim_array());
Related
I have an array of users with different userIds and I am trying to loop these array using a foreach loop. Inside that loop I am calling a function to get values of each users by passing their userid into a function. But its only passing one index of array.
My code
public function getDailyReportTest($orgId, $date)
{
$query = $this->db->query("SELECT * FROM `organization_users` WHERE orgId='7'");
$timestamp = strtotime($date);
$day = date('l', $timestamp);
$data = array();
$i = 0;
foreach ($query->result_array() as $row) {
$data[$i]['date'] = $date;
$data[$i]['day'] = $day;
$data[$i]['user_id'] = $row['orgUserId'];
$data[$i]['user_name'] = $row['orgUserName'];
$data[$i]['workingHours'] = self::getUserWorkingHours($data[$i]['user_id'],$date);
$delayTime=self::getUserDelayTime($row['orgUserId'],$date);
$shortTime=self::getUserShortTime($row['orgUserId'],$date);
$overTime=self::getUserOverTime($row['orgUserId'],$date);
$data[$i]['delayTime'] =$delayTime;
$data[$i]['shortTime'] =$shortTime;
$data[$i]['overTime'] =$overTime;
$data[$i]['shift1_start'] = self::getUserShiftStartTime($row['orgUserId'], $date);
$i=$i+1;
}
//return $data;
print_r($data);
die();
}
public function getUserShiftStartTime($userId, $date)
{
$query = $this->db->query("SELECT * FROM `office_employee_assigned_shifts` WHERE employeeId='$userId' &&shiftdate='$date'");
$entry = $query->num_rows();
$data = $query->result_array();
if($entry==0)
{
return NULL;
}
else
{
$shiftId = $data[0]['shiftId'];
$shiftquery = $this->db->query("SELECT startTimeSpan, endTimeSpan FROM `office_shift_time` WHERE officeShiftId='$shiftId'");
$dataShift = $shiftquery->result_array();
$startSpan = $dataShift[0]['startTimeSpan'];
$endSpan = $dataShift[0]['endTimeSpan'];
$firstPunchQuery = $this->db->query("SELECT punchTime AS firstPunch FROM `employee_punch_log` WHERE punchDate='$date' && employeeId='140' && punchTime BETWEEN '$startSpan' AND '$endSpan' AND punchType='1' LIMIT 1");
$punchEntryCount = $firstPunchQuery->num_rows();
if($punchEntryCount>0)
{
$dataFirstPunch = $firstPunchQuery->result_array();
$firstPunchStartTime = $dataFirstPunch[0]['firstPunch'];
return $firstPunchStartTime;
}
else
{
return "AB";
}
}
// return $entry;
}
It only passes the $data[1]['user_id'].
I want to pass $data[0]['user_id'], $data[1]['user_id'], $data[2]['user_id'] to the function
named getUserShiftStartTime($userId, $date)
Any Help?
Thanks for the help in advance
Then pass the current variable to your method:
self::getUserShiftStartTime($data[$i]['user_id'], $date);
I am trying to pass through any query to a function using PDO.
I have build up the array through a loop function and try to insert it into the execute(array(....)) function, but it's not getting through.
FUNCTION CODE
public function ShowData($sql,$variable)
{
$execute_string = "";
echo "<pre>";
print_r($variable);
echo "</pre>";
$q = $this->conn->prepare($sql);
for($i = 0; $i < sizeof($variable); $i++)
{
if($i != 0) $execute_string .= ",";
$placeholder = $i + 1;
$execute_string .= "':$placeholder' => '".$variable[$i]."'";
}
echo $sql."<br>";
echo $execute_string;
$q->execute(array($execute_string));
echo "<br>Execute Succeeded";
return $row = $q->fetchAll();
}
VIEWPAGE CODE
$author = "Nemoza";
$name = "MBICO_mailer";
$project = $data->ShowData("SELECT * FROM mbico_projects WHERE author=:1 AND name=:2", array($author,$name));
OUTPUT FROM FUNCTION W/ DEBUGGING
Array
(
[0] => Nemoza
[1] => MBICO_mailer
)
SELECT * FROM mbico_projects WHERE author=:1 AND name=:2
':1' => 'Nemoza',':2' => 'MBICO_mailer'
However, the 'Execute Succeeded' text is not being printed, and the execute(array...)) is not actually executing.
What am I doing wrong, and how else should I do it?
here's an example you can use:
public function ShowData($sql,$variable) {
$bind = [];
foreach ($variable as $key => $value) {
$ph = $key+1;
$bind[":" . $ph] = $value;
}
$stmt = $this->conn->prepare($sql);
$stmt->execute($bind);
return $stmt->fetchAll();
}
it's used like this:
$sql = 'select * from users where username = :1 or username = :2';
$bind = ['123', '456'];
$db->ShowData($sql, $bind);
as mentioned in the comments to your question, you need to send an array to execute() function, and not a string.
Managed to do it like this:
public function ShowData($sql,$variable)
{
$execute_string = array();
$q = $this->conn->prepare($sql);
foreach($variable as $item)
{
$execute_string[] = $item;
}
$q->execute($execute_string);
return $q->fetchAll();
}
$project = $data->ShowData("SELECT * FROM mbico_projects WHERE author=? AND title=?", array($author, $title));
I'm using this database MySQLi wrapper:
Class dbWrapper {
protected $_mysqli;
protected $_debug;
public function __construct($host, $username, $password, $database, $debug) {
$this->_mysqli = new mysqli($host, $username, $password, $database);
$this->_mysqli->set_charset("utf8");
$this->_debug = (bool) $debug;
if (mysqli_connect_errno()) {
if ($this->_debug) {
echo mysqli_connect_error();
debug_print_backtrace();
}
return false;
}
return true;
}
public function q($query) {
if ($query = $this->_mysqli->prepare($query)) {
if (func_num_args() > 1) {
$x = func_get_args();
$args = array_merge(array(func_get_arg(1)),
array_slice($x, 2));
$args_ref = array();
foreach($args as $k => &$arg) {
$args_ref[$k] = &$arg;
}
call_user_func_array(array($query, 'bind_param'), $args_ref);
}
$query->execute();
if ($query->errno) {
if ($this->_debug) {
echo mysqli_error($this->_mysqli);
debug_print_backtrace();
}
return false;
}
if ($query->affected_rows > -1) {
return $query->affected_rows;
}
$params = array();
$meta = $query->result_metadata();
while ($field = $meta->fetch_field()) {
$params[] = &$row[$field->name];
}
call_user_func_array(array($query, 'bind_result'), $params);
$result = array();
while ($query->fetch()) {
$r = array();
foreach ($row as $key => $val) {
$r[$key] = $val;
}
$result[] = $r;
}
$query->close();
return $result;
} else {
if ($this->_debug) {
echo $this->_mysqli->error;
debug_print_backtrace();
}
return false;
}
}
public function handle() {
return $this->_mysqli;
}
}
But when I make a query, for example SELECT This FROM Database, and I want to display the result, I have to echo $result[0]['This']. Why that? Why not $result['This']? I changed this:
$result = array();
while ($query->fetch()) {
$r = array();
foreach ($row as $key => $val) {
$r[$key] = $val;
}
$result[] = $r;
}
$query->close();
return $result;
to this:
$result = array();
while ($query->fetch()) {
foreach ($row as $key => $val) {
$result[$key] = $val;
}
$result[] = $r;
}
$query->close();
return $result;
But why do all the wrappers I see, return a multidimensional array?
Hope you understand me. Thank you!
The reason they return multidimensional arrays is because you can have more than one result.
So:
$data[0]['name'] is the first returned records name.
$data[1]['name'] is the second returned records name.
You can create a fetchRow() function which will always just return the first record when you only expect one row
return $data[0]
OR
a fetchOne()
return $data[0]['name']
When you only expect one field
Usually, when you're gathering results from a DB query, you have multiple rows.
--------------
- 1 --- This -
- 2 --- That -
--------------
So you get a multi-dimensional array in order to handle all the rows in one object.
...Is that not the case here?
EDIT:
$result = array();
while ($query->fetch()) {
$r = array();
foreach ($row as $key => $val) {
$r[$key] = $val;
}
$result[] = $r;
}
$query->close();
return $result;
in the above code, you are assigning each individual row to an index in the $results array. In order to access them, you need to provide $results[ROW_NUMBER][KEY_NAME];
Does that make sense?
I'm going to take a shot and say maybe try $query->fetch_row() instead of $query->fetch() (just a guess)
I've just changed all my sql queries to prepared statements using mysqli. To speed this process up I created a function (called performQuery) which replaces mysql_query. It takes the query, the bindings (like "sdss") and the variables to pass in, this then does all the perpared statement stuff. This meant changing all my old code was easy. My function returns a mysqli_result object using mysqli get_result().
This meant I could change my old code from:
$query = "SELECT x FROM y WHERE z = $var";
$result = mysql_query($query);
while ($row = mysql_fetch_assoc($result)){
echo $row['x'];
}
to
$query = "SELECT x FROM y WHERE z = ?";
$result = performQuery($query,"s",$var);
while ($row = mysql_fetch_assoc($result)){
echo $row['x'];
}
This works fine on localhost, but my web hosting server does not have mysqlnd available, therefore get_result() does not work. Installing mysqlnd is not an option.
What is the best way to go from here? Can I create a function which replaces get_result(), and how?
Here is a neater solution based on the same principle as lx answer:
function get_result( $Statement ) {
$RESULT = array();
$Statement->store_result();
for ( $i = 0; $i < $Statement->num_rows; $i++ ) {
$Metadata = $Statement->result_metadata();
$PARAMS = array();
while ( $Field = $Metadata->fetch_field() ) {
$PARAMS[] = &$RESULT[ $i ][ $Field->name ];
}
call_user_func_array( array( $Statement, 'bind_result' ), $PARAMS );
$Statement->fetch();
}
return $RESULT;
}
With mysqlnd you would normally do:
$Statement = $Database->prepare( 'SELECT x FROM y WHERE z = ?' );
$Statement->bind_param( 's', $z );
$Statement->execute();
$Result = $Statement->get_result();
while ( $DATA = $Result->fetch_array() ) {
// Do stuff with the data
}
And without mysqlnd:
$Statement = $Database->prepare( 'SELECT x FROM y WHERE z = ?' );
$Statement->bind_param( 's', $z );
$Statement->execute();
$RESULT = get_result( $Statement );
while ( $DATA = array_shift( $RESULT ) ) {
// Do stuff with the data
}
So the usage and syntax are almost identical. The main difference is that the replacement function returns a result array, rather than a result object.
I encountered the same problem and solved it using the code provided in the answer of
What's wrong with mysqli::get_result?
My function looks like this now (error handling stripped out for clarity):
function db_bind_array($stmt, &$row)
{
$md = $stmt->result_metadata();
$params = array();
while($field = $md->fetch_field()) {
$params[] = &$row[$field->name];
}
return call_user_func_array(array($stmt, 'bind_result'), $params);
}
function db_query($db, $query, $types, $params)
{
$ret = FALSE;
$stmt = $db->prepare($query);
call_user_func_array(array($stmt,'bind_param'),
array_merge(array($types), $params));
$stmt->execute();
$result = array();
if (db_bind_array($stmt, $result) !== FALSE) {
$ret = array($stmt, $result);
}
$stmt->close();
return $ret;
}
Usage like this:
$userId = $_GET['uid'];
$sql = 'SELECT name, mail FROM users WHERE user_id = ?';
if (($qryRes = db_query($db, $sql, 'd', array(&$userId))) !== FALSE) {
$stmt = $qryRes[0];
$row = $qryRes[1];
while ($stmt->fetch()) {
echo '<p>Name: '.$row['name'].'<br>'
.'Mail: '.$row['mail'].'</p>';
}
$stmt->close();
}
I found the anonymous advice posted as a note at the API documentation page for mysqli_stmt::get_result very useful (I couldn't think of a better way than the eval trick), as we very often want to fetch_array() on our result. However, because I wanted to cater for a generic database object, I found it a problem that the code assumed numeric array was fine for all callsites, and I needed to cater for all callers using assoc arrays exclusively. I came up with this:
class IImysqli_result {
public $stmt, $ncols;
}
class DBObject {
function iimysqli_get_result($stmt) {
$metadata = $stmt->result_metadata();
$ret = new IImysqli_result;
if (!$ret || !$metadata) return NULL; //the latter because this gets called whether we are adding/updating as well as returning
$ret->ncols = $metadata->field_count;
$ret->stmt = $stmt;
$metadata->free_result();
return $ret;
}
//this mimics mysqli_fetch_array by returning a new row each time until exhausted
function iimysqli_result_fetch_array(&$result) {
$stmt = $result->stmt;
$stmt->store_result();
$resultkeys = array();
$thisName = "";
for ( $i = 0; $i < $stmt->num_rows; $i++ ) {
$metadata = $stmt->result_metadata();
while ( $field = $metadata->fetch_field() ) {
$thisName = $field->name;
$resultkeys[] = $thisName;
}
}
$ret = array();
$code = "return mysqli_stmt_bind_result(\$result->stmt ";
for ($i=0; $i<$result->ncols; $i++) {
$ret[$i] = NULL;
$theValue = $resultkeys[$i];
$code .= ", \$ret['$theValue']";
}
$code .= ");";
if (!eval($code)) {
return NULL;
}
// This should advance the "$stmt" cursor.
if (!mysqli_stmt_fetch($result->stmt)) {
return NULL;
}
// Return the array we built.
return $ret;
}
}
I have 2 methods, that are pretty much exactly the same and I'd likie someone to help me refactor them:
public static function searchFromVideoRequest($word, $returnPropelObjects = false)
{
$c = new Criteria();
$c->addJoin(YoutubeVideoPeer::ID,ItemPeer::YOUTUBE_VIDEO_ID);
$c->addSelectColumn(self::TITLE);
$c->addSelectColumn(self::ID);
$c->add(ItemPeer::TITLE, '%'.$word.'%', Criteria::LIKE);
$c->addAnd(self::YOUTUBE_VIDEO_ID, null, Criteria::ISNOTNULL);
$c->addAscendingOrderByColumn(self::TITLE);
if ($returnPropelObjects)
return self::doSelect($c);
$stmt = self::doSelectStmt($c);
$results = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$results[] = $row;
}
return $results;
}
public static function searchFromFlickrRequest($word, $returnPropelObjects = false)
{
$c = new Criteria();
$c->addJoin(FlickrPhotoPeer::ID,ItemPeer::FLICKR_PHOTO_ID);
$c->addSelectColumn(self::TITLE);
$c->addSelectColumn(self::ID);
$c->add(ItemPeer::TITLE, '%'.$word.'%', Criteria::LIKE);
$c->addAnd(self::FLICKR_PHOTO_ID, null, Criteria::ISNOTNULL);
$c->addAscendingOrderByColumn(self::TITLE);
if ($returnPropelObjects)
return self::doSelect($c);
$stmt = self::doSelectStmt($c);
$results = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$results[] = $row;
}
return $results;
}
Thanks
To refactor such methods you can split up them into a few methods that will contain common code and make them private, so no one can use them outside the class:
public static function searchFromVideoRequest($word, $returnPropelObjects = false)
{
$c = self::buildSearchCriteria($word);
$c->addJoin(YoutubeVideoPeer::ID,ItemPeer::YOUTUBE_VIDEO_ID);
$c->addAnd(self::YOUTUBE_VIDEO_ID, null, Criteria::ISNOTNULL);
return self::getSearchResult($c, $returnPropelObjects);
}
public static function searchFromFlickrRequest($word, $returnPropelObjects = false)
{
$c = self::buildSearchCriteria($word);
$c->addJoin(FlickrPhotoPeer::ID,ItemPeer::FLICKR_PHOTO_ID);
$c->addAnd(self::FLICKR_PHOTO_ID, null, Criteria::ISNOTNULL);
return self::getSearchResult($c, $returnPropelObjects);
}
private static function buildSearchCriteria($word)
{
$c = new Criteria();
$c->addSelectColumn(self::TITLE);
$c->addSelectColumn(self::ID);
$c->add(ItemPeer::TITLE, '%'.$word.'%', Criteria::LIKE);
$c->addAscendingOrderByColumn(self::TITLE);
return $c;
}
private static function getSearchResult($c, $returnPropelObjects)
{
if ($returnPropelObjects)
return self::doSelect($c);
$stmt = self::doSelectStmt($c);
$results = array();
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$results[] = $row;
}
return $results;
}
PS: And I think the question is OK.