I don't manage to fill a table with a PHP Object with PDO and an object created from a JSON file. Do you see where the error comes from?
I use PHP5 & PostgreSQL
The code I wrote sucessfully adds the lines, but only the first column (field) of each row is filled, the others remain white.
My table structure looks like this:
CREATE TABLE ' . $infoTableName . ' (field text,type text,expefactor boolean,iduser boolean,idcontext boolean,idaction boolean,params boolean,comment text)
My object looks like this:
object(stdClass)[3]
public 'timestamp' =>
object(stdClass)[4]
public 'idagent' => boolean false
public 'idcontext' => boolean false
public 'idaction' => boolean false
public 'comment' => string 'ffff' (length=4)
public 'order' =>
object(stdClass)[5]
public 'idagent' => boolean false
public 'idcontext' => boolean false
public 'idaction' => boolean false
public 'comment' => string 'none' (length=4)
public 'test' =>
object(stdClass)[6]
public 'idagent' => boolean false
public 'idcontext' => boolean true
public 'idaction' => boolean false
public 'comment' => string 'y' (length=1)
And finally the PHP code:
$structure = json_decode($_POST['structure']);
$query = "INSERT INTO " . $infoTableName . " (field, iduser, idcontext, idaction, comment) VALUES (:field, :idagent, :idcontext, :idaction, :comment)"; //Prequery
$stmt = $db->prepare($query);
$stmt->bindParam(':field', $key);
$stmt->bindParam(':idagent', $value->idagent);
$stmt->bindParam(':idcontext', $value->idcontext);
$stmt->bindParam(':idaction', $value->idaction);
$stmt->bindParam(':comment', $value->comment);
foreach ($structure as $key => &$value) {
try {
var_dump($stmt->execute());
} catch (PDOException $e) {
var_dump($e->getMessage());
}
}
Do you see the error?
Thanks a lot.
EDIT: It looks like I am asking a too much with object in binding functions, still, here is a little workaround:
$stmt->bindParam(':field', $key);
$stmt->bindParam(':idagent', $idagent);
$stmt->bindParam(':idcontext', $idcontext);
$stmt->bindParam(':idaction', $idaction);
$stmt->bindParam(':comment', $comment);
foreach ($structure as $key => &$value) {
$idagent = $value->idagent;
$idcontext = $value->idcontext;
$idaction = $value->idaction;
$comment = $value->comment;
try {
var_dump($stmt->execute());
} catch (PDOException $e) {
var_dump($e->getMessage());
}
}
The reason bindParam() doesn't work is when I iterate thru the $structure, $value is reinstanciated, resulting in the references being changed... I first thought &$value would help, but it looks like not.
Like they do here: ...
No, they do not. Look again:
$stmt->bindParam(':name', $name);
$name = 'one';
$stmt->execute();
They are binding the variable $name by reference and then assign a value to $name.
You on the other hand are doing:
$stmt->bindParam(':idagent', $value->idagent);
foreach ($structure as $key => &$value) {
$stmt->execute();
}
You are binding $value->idagent by reference (I'm not actually sure if that works, creating an implicit object...?!), and then you're reference-overwriting $value. If at all, you should be assigning a value to $value->idagent, which was bound. Just replacing the $value object is not the same thing at all. PHP isn't so intelligent that it tracks that you bound the idagent attribute of that object and will reconstruct that after you have switched the underlying object. That's a little too meta.
I think in this case it's most useful to use bindValue inside your foreach loop and bind the existing values there.
$stmt = $db->prepare($query);
foreach ($structure as $key => $value) {
$stmt->bindValue(':field', $key);
$stmt->bindValue(':idagent', $value->idagent);
$stmt->bindValue(':idcontext', $value->idcontext);
$stmt->bindValue(':idaction', $value->idaction);
$stmt->bindValue(':comment', $value->comment);
$stmt->execute()
}
It looks like I am asking a too much with object in binding functions, still, here is a little workaround:
$stmt->bindParam(':field', $key);
$stmt->bindParam(':idagent', $idagent);
$stmt->bindParam(':idcontext', $idcontext);
$stmt->bindParam(':idaction', $idaction);
$stmt->bindParam(':comment', $comment);
foreach ($structure as $key => &$value) {
$idagent = $value->idagent;
$idcontext = $value->idcontext;
$idaction = $value->idaction;
$comment = $value->comment;
try {
var_dump($stmt->execute());
} catch (PDOException $e) {
var_dump($e->getMessage());
}
}
The reason bindParam() doesn't work is when I iterate thru the $structure, $value is reinstanciated, resulting in the references being changed... I first thought &$value would help, but it looks like not.
Related
So, i have a little trouble:
I have a class, let's name it "Menu", also, i have an array, which provides an elements for "Menu", it looks like that
class Menu {
private $_data = [];
public function __construct() {
$this->_data = array(
"Parent1" => array(
"Child1" => array(
"id" => 1,
"minQuantity" => x,
"maxQuantity" => x,
"cost" => x,
),
"Child2"...
),
"ParentX" => array(
"ChildXX"...
)
/* AND SO ON */
);
}
}
Also, in "Menu" i have a function, which by recursion try to find an element of the $this->_data with specified value, function looks like that:
public function findChildById($parent = null, $id = null) {
foreach ($parent as $_parent => $_child) {
if (array_key_exists($id, $parent)) var_dump($parent);
if (is_array($_child)) $this->findChildById($_child, $id);
}
}
But, when it finds needed element, and I try to return it - result is always NULL. Using var_dump leads to obvious output, I can see what exactly what I need, but i cant return an element from function. What should i do?
Since you only try to find one element, it should be enough to pass the return value up the recursion stack. E.g. like this:
public function findChildById($parent = null, $id = null) {
foreach ($parent as $_parent => $_child) {
if (array_key_exists($id, $parent)) return $parent; //first return
if (is_array($_child)) {
$tmp = $this->findChildById($_child, $id);
if (!is_null($tmp)) return $tmp; //if a deeper step found sth. pass it up
}
}
}
The reason for the NULLs you get, must be, because PHP functions return NULL implicitly when the code does not reach a return statement.
I have below PDO function that executes a Mysql query.
public function run($sql, array $params = NULL) {
$statement = $this->pdo->prepare($sql);
if (!is_null($params)) {
foreach ($params as $key) {
$statement->bindParam(":n", $key);
}
}
$statement->execute();
return $statement->fetchAll(PDO::FETCH_CLASS);
}
This only works with single parameters (see my previous question)
So i tried modifying the foreach in the function to
foreach ($params as $key => $value) {
$statement->bindParam($key, $value);
}
I run the query as
$variation = $query->run(
"SELECT url, title, sale_price
FROM product
where category_id = :category
and url != :url",
[ ":category" => $data[0]->category_id, ":url" => $filePathArray[1] ]
);
It returns an empty set.
This function is not necessary. You can pass the array of parameters directly to $statement->execute() as explained in the documentation for PDOStatement::execute().
It is as safe as using bindParam(), it protects against SQL injection just the same.
The only downside is that you cannot specify the type of each parameter, but that isn't necessary in most cases, and in this example you were not using it anyway so you won't loose anything.
Is it possible to set multiple properties at a time for an object in php?
Instead of doing:
$object->prop1 = $something;
$object->prop2 = $otherthing;
$object->prop3 = $morethings;
do something like:
$object = (object) array(
'prop1' => $something,
'prop2' => $otherthing,
'prop3' => $morethings
);
but without overwriting the object.
Not like the way you want. but this can be done by using a loop.
$map = array(
'prop1' => $something,
'prop2' => $otherthing,
'prop3' => $morethings
);
foreach($map as $k => $v)
$object->$k = $v;
See only 2 extra lines.
You should look at Object Oriented PHP Best Practices :
"since the setter functions return $this you can chain them like so:"
$object->setName('Bob')
->setHairColor('green')
->setAddress('someplace');
This incidentally is known as a fluent interface.
I would recommend you don't do it. Seriously, don't.
Your code is much MUCH cleaner the first way, it's clearer of your intentions, and you aren't obfocusing your code to the extent where sometime in the future someone would look at your code and think "What the hell was the idiot thinking"?
If you insist on doing something which is clearly the wrong way to go, you can always create an array, iterate it and set all the properties in a loop. I won't give you code though. It's evil.
You could write some setters for the object that return the object:
public function setSomething($something)
{
$this->something = $something;
return $this; //this will return the current object
}
You could then do:
$object->setSomething("something")
->setSomethingelse("somethingelse")
->setMoreThings("some more things");
You would need to write a setter for each property as a __set function is not capable of returning a value.
Alternatively, set a single function to accept an array of property => values and set everything?
public function setProperties($array)
{
foreach($array as $property => $value)
{
$this->{$property} = $value;
}
return $this;
}
and pass in the array:
$object->setProperties(array('something' => 'someText', 'somethingElse' => 'more text', 'moreThings'=>'a lot more text'));
I realise this is an old question but for the benefit of others that come across it, I solved this myself recently and wanted to share the result
<?php
//Just some setup
header('Content-Type: text/plain');
$account = (object) array(
'email' => 'foo',
'dob'=>((object)array(
'day'=>1,
'month'=>1,
'year'=>((object)array('century'=>1900,'decade'=>0))
))
);
var_dump($account);
echo "\n\n==============\n\n";
//The functions
function &getObjRef(&$obj,$prop) {
return $obj->{$prop};
}
function updateObjFromArray(&$obj,$array){
foreach ($array as $key=>$value) {
if(!is_array($value))
$obj->{$key} = $value;
else{
$ref = getObjRef($obj,$key);
updateObjFromArray($ref,$value);
}
}
}
//Test
updateObjFromArray($account,array(
'id' => '123',
'email' => 'user#domain.com',
'dob'=>array(
'day'=>19,
'month'=>11,
'year'=>array('century'=>1900,'decade'=>80)
)
));
var_dump($account);
Obviously there are no safeguards built in. The main caveat is that the updateObjFromArray function assumes that for any nested arrays within $array, the corresponding key in $obj already exists and is an object, this must be true or treating it like an object will throw an error.
Hope this helps! :)
I wouldn't actually do this....but for fun I would
$object = (object) ($props + (array) $object);
you end up with an stdClass composed of $objects public properties, so it loses its type.
Method objectThis() to transtypage class array properties or array to stdClass. Using direct transtypage (object) would remove numeric index, but using this method it will keep the numeric index.
public function objectThis($array = null) {
if (!$array) {
foreach ($this as $property_name => $property_values) {
if (is_array($property_values) && !empty($property_values)) {
$this->{$property_name} = $this->objectThis($property_values);
} else if (is_array($property_values) && empty($property_values)) {
$this->{$property_name} = new stdClass();
}
}
} else {
$object = new stdClass();
foreach ($array as $index => $values) {
if (is_array($values) && empty($values)) {
$object->{$index} = new stdClass();
} else if (is_array($values)) {
$object->{$index} = $this->objectThis($values);
} else if (is_object($values)) {
$object->{$index} = $this->objectThis($values);
} else {
$object->{$index} = $values;
}
}
return $object;
}
}
Using the following:
$last_book = tz_books::getLast($request->db, "WHERE book_id='{$request->book_id}'");
I get the following php object array,
[0] => tz_books Object
(
[db:tz_books:private] => com Object
[id] => 64BEC207-CA35-4BD2
[author_id] => 4F4755B4-0CE8-4251
[book_id] => 8FC22AA0-4A60-4BFC
[date_due] => variant Object
)
I then want to use the author_id, but for some reason it's not working.
Trying to use:
$tz_books->author_id;
Using print_r($last_book); prints the array to the console just fine. And Doing the following just to see if the correct variable was being used:
$author = $tz_books->author_id;
print_r($author);
Nothing is printed to the console, and even after digging through the php manual and trying a lot of alternatives, I can't seem to grab that variable. I'm hoping i'm making a rookie mistake and overlooking something stupid. Thank you for any help!
Edit: Class definition
private $db;
public $id;
public $author_id;
public $book_id;
public $date_due;
public function __construct($db, $values=null) {
$this->db = $db;
if ( $values != null ) {
foreach ( $values as $var => $value ) {
$this->$var = $value;
}
}
}
public static function retrieveAll($db, $where='', $order_by='') {
$result_list = array();
$query = 'SELECT '.
'id, '.
'author_id, '.
'book_id, '.
'date_due '.
"FROM tz_books $where $order_by";
$rs = $db->Execute($query);
while ( !$rs->EOF ) {
$result_list[] = new tz_books($db, array(
'id' => clean_id($rs->Fields['id']->Value),
'author_id' => clean_id($rs->Fields['author_id']->Value),
'book_id' => clean_id($rs->Fields['book_id']->Value),
'date_due' => $rs->Fields['date_due']->Value,
));
$rs->MoveNext();
}
$rs->Close();
return $result_list;
}
Your result object seems to be an array of books with 1 element.
Try
echo $tz_books[0]->author_id;
BTW, it also looks like you're escaping input by putting single quotes. This is not a reliable/recommended method. Use a database-specific escape function like this
I have the this method:
public function search($searchKey=null, $summary=null, $title=null, $authors=null, $paginationPage=0) {
...
}
And I'm trying to retrieve all parameters with this:
$Class = new Search();
// Get parameters
$ReflectionMethod = new \ReflectionMethod($Class, "search");
try {
foreach($ReflectionMethod->getParameters() AS $Parameter) {
if(array_key_exists($Parameter->name, $this->params)) {
$parameters[$Parameter->name] = $this->params[$Parameter->name];
} elseif($Parameter->isDefaultValueAvailable()) {
$paramaters[$Parameter->name] = $Parameter->getDefaultValue();
} else {
...
}
} catch(\Exception $e) {
...
}
// Call function
return call_user_func_array(array($Class, "search"), $parameters);
My $this->params has this content:
array
'paginationPage' => int 2
'id' => int 30
'searchKey' => string 'test' (length=4)
Because $summary, $title and $authors are not present, they will get their default value which is null. When assigning a null value to an argument, it will be skipped which results in a $parameters array that looks like this:
array
'searchKey' => string 'test' (length=4)
'paginationPage' => int 2
Which result in a method call like:
public function search('test', 2, null, null, 0) {
...
}
While it should be:
public function search('test', null, null, null, 2) {
...
}
Hopefully you see the problem. How can I make sure those null values are also put into my $parameters array. Adding an invalid value is not possible, because it is user input, so that can be basically everything.
Edit
In the example above the method search is hardcoded. But one of the simplified things is that search is actually a variable and because of that search can be anything. This means that I don't know what the parameters of the method are and I can't predefine them before the foreach loop. The solution of predefining the parameters is actually exactly what this code should be doing.
How about pre-initializing $parameters before entering the foreach loop:
$parameters = array(
$searchKey => null,
$summary => null,
$title => null,
$authors => null,
$paginationPage => 0
);
Oh my... It was just a simple typo:
...
} elseif($Parameter->isDefaultValueAvailable()) {
$paramaters[$Parameter->name] = $Parameter->getDefaultValue();
} else {
...
Shame on me!