Count number of variables in object? - PHP - php

Is there a way to count the number of variables in an object?
I have a object that is created dynamically, and I want to add each of the properties to a query to update these properties into the database.
The variable $oProperties is an object:
public function update_model ($id, $oProperties)
{
$SQL = "UPDATE `table` SET ";
$count = 0;
foreach($oProperties as $property=>$value)
{
$count++;
$SQL .= strtolower($property)." = '".$value."'";
if($count !== $oProperties::count()) {$SQL .= ", ";}
}
$SQL .= " WHERE id='".$id."';";
}
I need to know the amount of properties in the object to know when to stop adding the comma to the query.

You can use get_object_vars:
class foo {
private $a;
public $b = 1;
public $c;
private $d;
static $e;
}
$test = new foo;
var_dump(get_object_vars($test));
Result:
array(2) {
["b"]=>
int(1)
["c"]=>
NULL
}
or if your object has type ArrayObject, you can use count method:
$arrayobj = new ArrayObject(array('first','second','third'));
var_dump($arrayobj->count());
But I think will be better use something like that:
public function update_model ($id, $oProperties)
{
$SQL = "UPDATE `table` SET ";
$properties = [];
foreach($oProperties as $property=>$value)
{
$properties[] = strtolower($property)." = '".$value."'";
}
$SQL .= implode(', ', $properties);
$SQL .= " WHERE id='{$id}';";
return $SQL;
}

$arrayObj = (array)($oProperties);
print_r(count($arrayObj));

Related

Convert NoSQL like syntax to MySQL syntax

This is mysql table structure
item_id
StockNo
SizeCd
1
12003
UNIT
2
12007
JOGO
3
12008
PACOTE
4
12033
JOGO
5
12034
JOGO
6
12038
UNIT
I'm using plugin called DevExtreme for remote data grid. It's API request looks like below.
{
from: get_data
skip: 0
take: 50
requireTotalCount: true
filter: [["SizeCd","=","UNIT"],"or",["SizeCd","=","JOGO"]]
}
Where filter is what I need help with. What I want is I want to convert this string into MySQL where condition syntax.
I tried using php functions like array_merge join but couldn't get it to work. Sometimes it place quotes to both sides or sometimes quotes were missing. It should be like field name without quotes and value with quotes. Like in mysql where syntax.
Sorry for bad formatting and grammar mistakes.
For this array:
$array = [["SizeCd","=","UNIT"],"or",["SizeCd","=","JOGO"],"or",["SizeCd","=","PACOTE"]];
For PDO
You can use the following functions:
function arrayToQuery(string $tableName, array $array) : string
{
$select = "SELECT * FROM `{$tableName}` WHERE ";
foreach($array as $item) {
if(is_array($item)) {
$select .= "`{$item[0]}` {$item[1]} ?";
} else {
$select .= " {$item} ";
}
}
return $select;
}
function arrayToParams(array $array) : array
{
$return = [];
foreach($array as $item) {
if(is_array($item)) {
$return[] = $item[2];
}
}
return $return;
}
var_dump(
arrayToQuery("x", $array),
arrayToParams($array)
);
Output:
string(66) "SELECT * FROM `x` WHERE `SizeCd` = ? or `SizeCd` = ? or `SizeCd` = ?"
array(3) {
[0]=>
string(4) "UNIT"
[1]=>
string(4) "JOGO"
[2]=>
string(6) "PACOTE"
}
Example using PDO
$conn = /* your conn object */;
$sql = arrayToQuery("your_table_name", $array);
$stmt = $conn->prepare($sql);
$stmt->execute(arrayToParams($array));
Update: For Mysqli
For mysqli you can use the following function:
function arrayToQueryMysqli($mysqli, string $table, array $array) : string
{
$select = "SELECT * FROM `{$table}` WHERE ";
foreach($array as $item) {
if(is_array($item)) {
$select .= "`{$item[0]}` {$item[1]} '" . $mysqli->real_escape_string($item[2]) . "'";
} else {
$select .= " {$item} ";
}
}
return $select;
}
$mysqli = new mysqli(/* Your settings */);
$query = arrayToQueryMysqli($mysqli, "tablename", $array);
$result = $mysqli->query($query);
var_dump($result);

php + mysql query returning only a single row (std class) from class function

Can you tell me why this returns only the last row of my query?
As you see I'm extracting as std class. Also I already tried different approaches like a foreach key=>value inside the while but it does not help. I can't populate $out correctly.
class myclass {
function Query($sql){
$results = $this->db->query($sql);
if (mysqli_num_rows($results)<1){
throw new Exception('NoResults');
}
$out = new stdClass;
while ($r = $results->fetch_object()){
$out = $r;
}
return $out;
$out = null;
}
}
}
---------------
$client = new myclass;
$sql = "SELECT * FROM books";
$q = $client->Query($sql);
print_r($q);
You just need to change those lines:
$out = new stdClass;
while ($r = $results->fetch_object()){
$out = $r;
}
to those ones:
$out = []; // array that will hold all the objects
while ($r = $results->fetch_object()){
array_push($out, $r); // add to the array the current object
}
return $out; //return the array with the objects
You are overwriting $out at every iteration of the while, so you'll have only the last result in the return. You could use an array and append the results (it could be an array of stdClass objects), and then you'll be able to work with it with a simple loop
class myclass {
function Query($sql){
$results = $this->db->query($sql);
if (mysqli_num_rows($results)<1){
throw new Exception('NoResults');
}
//copied this piece of code from #Berto99 answer from this same question
$out = []; // array that will hold all the objects
while ($r = $results->fetch_object()){
array_push($out, $r); // add to the array the current object
}
return $out; //return the array with the objects
}
}
---------------
$client = new myclass;
$sql = "SELECT * FROM books";
$q = $client->Query($sql);
foreach($q as $resultLine){
//do whatever you need to do here
}
Your $r is object. You dont need stdClass. You need to add your objects to $out array.
function Query($sql)
{
$results = $this->db->query($sql);
if (mysqli_num_rows($results) < 1) {
throw new Exception('NoResults');
}
$out = new stdClass;
$i=0;
while ($r = $results->fetch_object()){
$out->{$i} = $r;
$i++
}
return $out;
}

PHP Reference for MySQL query

My function:
function sql_query($s, $x) {
$query = mysql_query($s);
global $mysql;
while($mysql = mysql_fetch_array($query)) {
return;
}
}
Now it's work only with $mysql variable:
echo $mysql['username'];
How to make it works only with:
sql_query("select * from users where id = '1' limit 1", "varname");
$varname['username'];
I want to set a SQL Query and Variable name in function, like:
sql_query("sqlquery", "variable");
echo $variable['id'];
Thanks for reply!
function sql_query($s, &$x) {
global $mysql;
$query = mysql_query($s);
$result = mysql_fetch_array($query);
foreach($result as $key => $value) {
$x[$key] = $value;
}
}
This should assign each variable that is returned by the query to a key in array $x (assuming it is an array). Notice that I am passing $x by reference instead of by value, eliminating the need to return anything.

MySQLi Query Returning Single Result -- Should Be Array of Results

Having some trouble with the following code. I've created a class to manage the DB connection, using what you see below as queryPreparedQuery and works fine when getting data for a single user, or any data that returns a single result using something like this...
include 'stuff/class_stuff.php';
function SweetStuff() {
$foo = new db_connection();
$foo->queryPreparedQuery("SELECT Bacon, Eggs, Coffee FROM Necessary_Items WHERE Available = ?",$bool);
$bar = $foo->Load();
$stuff = 'Brand of Pork is '.$bar['Bacon'].' combined with '.$bar['Eggs'].' eggs and '.$bar['Coffee'].' nectar for energy and heart failure.';
return $stuff;
}
echo SweetStuff();
Problem is, I want to build the functionality in here to allow for a MySQL query which returns multiple results. What am I missing? I know it's staring me right in the face...
class db_connection
{
private $conn;
private $stmt;
private $result;
#Build a mysql connection
public function __construct($host="HOST", $user="USER", $pass="PASS", $db="DB_NAME")
{
$this->conn = new mysqli($host, $user, $pass, $db);
if(mysqli_connect_errno())
{
echo("Database connect Error : "
. mysqli_connect_error());
}
}
#return the connected connection
public function getConnect()
{
return $this->conn;
}
#execute a prepared query without selecting
public function execPreparedQuery($query, $params_r)
{
$stmt = $this->conn->stmt_init();
if (!$stmt->prepare($query))
{
echo("Error in $statement when preparing: "
. mysqli_error($this->conn));
return 0;
}
$types = '';
$values = '';
$index = 0;
if(!is_array($params_r))
$params_r = array($params_r);
$bindParam = '$stmt->bind_param("';
foreach($params_r as $param)
{
if (is_numeric($param)) {
$types.="i";
}
elseif (is_float($param)) {
$types.="d";
}else{
$types.="s";
}
$values .= '$params_r[' . $index . '],';
$index++;
}
$values = rtrim($values, ',');
$bindParam .= $types . '", ' . $values . ');';
if (strlen($types) > 0)
{
//for debug
//if(strpos($query, "INSERT") > 0)
//var_dump($params_r);
eval($bindParam);
}
$stmt->execute();
return $stmt;
}
#execute a prepared query
public function queryPreparedQuery($query, $params_r)
{
$this->stmt = $this->execPreparedQuery($query, $params_r);
$this->stmt->store_result();
$meta = $this->stmt->result_metadata();
$bindResult = '$this->stmt->bind_result(';
while ($columnName = $meta->fetch_field()) {
$bindResult .= '$this->result["'.$columnName->name.'"],';
}
$bindResult = rtrim($bindResult, ',') . ');';
eval($bindResult);
}
#Load result
public function Load(&$result = null)
{
if (func_num_args() == 0)
{
$this->stmt->fetch();
return $this->result;
}
else
{
$res = $this->stmt->fetch();
$result = $this->result;
return $res;
}
}
#Load result
public function Execute(&$result = null)
{
if (func_num_args() == 0)
{
$this->stmt->fetch_array();
return $this->result;
}
else
{
$res = $this->stmt->fetch_array();
$result = $this->result;
return $res;
}
}
private function bindParameters(&$obj, &$bind_params_r)
{
call_user_func_array(array($obj, "bind_param"), $bind_params_r);
}
}
UPDATE
Got this to work with Patrick's help. Was able to find the following code with the help of this question, and with a few tweaks, it works beautifully. Added the following after the execute() statement in ExecPreparedQuery, returning an array at the very end instead of the single result:
# these lines of code below return multi-dimentional/ nested array, similar to mysqli::fetch_all()
$stmt->store_result();
$variables = array();
$data = array();
$meta = $stmt->result_metadata();
while($field = $meta->fetch_field())
$variables[] = &$data[$field->name]; // pass by reference
call_user_func_array(array($stmt, 'bind_result'), $variables);
$i=0;
while($stmt->fetch())
{
$array[$i] = array();
foreach($data as $k=>$v)
$array[$i][$k] = $v;
$i++;
}
# close statement
$stmt->close();
return $array;
As a result of the altered code, I changed the call to interpret multidimensional array data rather than a single result, of course. Thanks again!
In your Execute function you are calling $this->stmt>fetch_array().
That function only returns an array of a single row of the result set.
You probably want:
$this->stmt->fetch_all()
Update
To retrieve the entire result set from a prepared statement:
$this->stmt->store_result()

Use one bind_param() with variable number of input vars

I try to use variable binding like this:
$stmt = $mysqli->prepare("UPDATE mytable SET myvar1=?, myvar2=... WHERE id = ?")) {
$stmt->bind_param("ss...", $_POST['myvar1'], $_POST['myvar2']...);
but some of the $_POST['...'] might be empty so I don't want to update them in the DB.
It's not practical to take into account all the different combination of empty $_POST['...'] and although I can build the string " UPDATE mytable SET..." to my needs, bind_param() is a different beast.
I could try building its call as a string and use eval() on it but it doesn't feel right :(
You could use the call_user_func_array function to call the bind_param method with a variable number or arguments:
$paramNames = array('myvar1', 'myvar2', /* ... */);
$params = array();
foreach ($paramNames as $name) {
if (isset($_POST[$name]) && $_POST[$name] != '') {
$params[$name] = $_POST[$name];
}
}
if (count($params)) {
$query = 'UPDATE mytable SET ';
foreach ($params as $name => $val) {
$query .= $name.'=?,';
}
$query = substr($query, 0, -1);
$query .= 'WHERE id = ?';
$stmt = $mysqli->prepare($query);
$params = array_merge(array(str_repeat('s', count($params))), array_values($params));
call_user_func_array(array(&$stmt, 'bind_param'), $params);
}
This is what I use to do mysqli prepared statements with a variable amount of params. It's part of a class I wrote. It propably is overkill for what you need but it should show you the right direction.
public function __construct($con, $query){
$this->con = $con;
$this->query = $query;
parent::__construct($con, $query);
//We check for errors:
if($this->con->error) throw new Exception($this->con->error);
}
protected static $allowed = array('d', 'i', 's', 'b'); //allowed types
protected static function mysqliContentType($value) {
if(is_string($value)) $type = 's';
elseif(is_float($value)) $type = 'd';
elseif(is_int($value)) $type = 'i';
else throw new Exception("type of '$value' is not string, int or float");
return $type;
}
//This function checks if a given string is an allowed mysqli content type for prepared statement (s, d, b, or i)
protected static function mysqliAllowedContentType($s){
return in_array($s, self::$allowed);
}
public function feed($params){
//These should all be empty in case this gets used multiple times
$this->paramArgs = array();
$this->typestring = '';
$this->params = $params;
$this->paramArgs[0] = '';
$i = 0;
foreach($this->params as $value){
//We check the type:
if(is_array($value)){
$temp = array_keys($value);
$type = $temp[0];
$this->params[$i] = $value[$type];
if(!self::mysqliAllowedContentType($type)){
$type = self::mysqliContentType($value[$type]);
}
}
else{
$type = self::mysqliContentType($value);
}
$this->typestring .= $type;
//We build the array of values we pass to the bind_params function
//We add a refrence to the value of the array to the array we will pass to the call_user_func_array function. Thus say we have the following
//$this->params array:
//$this->params[0] = 'foo';
//$this->params[1] = 4;
//$this->paramArgs will become:
//$this->paramArgs[0] = 'si'; //Typestring
//$this->paramArgs[1] = &$this->params[0];
//$this->paramArgs[2] = &$this->params[1].
//Thus using call_user_func_array will call $this->bind_param() (which is inherented from the mysqli_stmt class) like this:
//$this->bind_param( 'si', &$this->params[0], &$this->params[1] );
$this->paramArgs[] = &$this->params[$i];
$i++;
}
unset($i);
$this->paramArgs[0] = $this->typestring;
return call_user_func_array(array(&$this, 'bind_param'), $this->paramArgs);
}
You use it like this:
$prep = new theClassAboveHere( $mysqli, $query );
$prep->feed( array('string', 1, array('b', 'BLOB DATA') );
The class should extend the mysqli_stmt class.
I hope this helps you in the right direction.
If you wan't I could also post the whole class, it includes variable results binding.
It is marginally more clear to build your statement using an array:
$params = array();
$fragments = array();
foreach($_POST as $col => $val)
{
$fragments[] = "{$col} = ?";
$params[] = $val;
}
$sql = sprintf("UPDATE sometable SET %s", implode(", ", $fragments));
$stmt = $mysqli->prepare($sql);
$stmt->bind_param($params);
array_insert does not exist, i'm guessing he refers to some home made function, but i'm not sure exactly what it does ... inserts the parameter types onto the array somewhere in the beginning i would guess since the value 0 is passed but hey it could be in the end too ;)
Build it as a string, but put your values into an array and pass that to bindd_param. (and substitute ?'s for values in your SQL string.
$stmt = $mysqli->prepare("UPDATE mytable SET myvar1=?, myvar2=... WHERE id = ?")) {
$stmt->bind_param("ss...", $_POST['myvar1'], $_POST['myvar2']...);
For example:
$args = array();
$sql = "UPDATE sometable SET ";
$sep = "";
$paramtypes = "";
foreach($_POST as $key => $val) {
$sql .= $sep.$key." = '?'";
$paramtypes .= "s"; // you'll need to map these based on name
array_push($args, $val);
$sep = ",";
}
$sql .= " WHERE id = ?";
array_push($args, $id);
array_insert($args, $paramtypes, 0);
$stmt = $mysqli->prepare($sql);
call_user_func_array(array(&$stmt, 'bindparams'), $array_of_params);
$stmt->bind_param($args);

Categories