I have a PHP class called Product:
class Product {
$id;
$name;
}
And another class that get data from database:
$stm = $this->dsn->prepare($sql);
$stm->execute();
$rst = $stm->fetchAll(PDO::FETCH_ASSOC);
How can I convert this PDO resultset ($rst) to an array of objects Product?
Use the PDO::FETCH_CLASS argument.
class Product {
public $id;
public $name;
}
$stm = $this->dsn->prepare($sql);
$stm->execute();
$result = $stm->fetchAll( PDO::FETCH_CLASS, "Product" );
http://php.net/manual/en/pdostatement.fetchall.php
Just change the way you're calling fetchAll()
$rst = $stm->fetchAll(PDO::FETCH_CLASS, 'Product');
My approach in this case would be to use a helper function within the Product class that builds a new instance of the object and returns it provided the inputs from the PDO.
Such as
public static function buildFromPDO($data) {
$product = new Product();
$product->id = $data["id"];
$product->name = $data["name"];
return $product;
}
Then inside of your PDO call, loop through the return and array_push onto an array containing all your products built via this function.
$products = array();
foreach ($rst as $r) {
array_push($products, Product::buildFromPDO($r));
}
You also might want to consider using an ORM if it seems like you'll be doing a ton of this kind of stuff.
You have to write a method to do it.
class Product {
$id;
$name;
public function loadData($data){
$this->id = $data['id'];
$this->name = $data['name'];
}
}
$Product = new Product();
$Product->loadData($database_results);
Or, if you're going to be doing this for every object, use a constructor..
class Product {
$id;
$name;
public function __construct($id, $pdo){
$pdo->prepare("select * from table where id = :id");
// do your query, then...
$this->id = $data['id'];
$this->name = $data['name'];
}
}
$Product = new Product($id, $pdo);
You can use constructor arguments (http://php.net/manual/en/pdostatement.fetchall.php)
$result = $stm->fetchAll( PDO::FETCH_CLASS, "Product", array('id','name'));
Note: properties must be public
Related
I'm wanting to create a new instance of my Class and assign it's attributes the values that are returned. The reason for this is I'm creating a series of methods inheriting from the calling class, as opposed to using static methods which I already had working.
Example of what I'm using currently:
public static function findById($id) {
$id = self::escapeParam($id);
$idVal = is_int($id) ? "i" : "s";
$sql = "SELECT * FROM ".static::$db_table." WHERE id = ? LIMIT 1";
return static::findByQuery($sql,$idVal,$id);
}
public static function findByQuery($sql,$bindChar = '',$bindVal = '') {
try {
$callingClass = get_called_class();
$object = new $callingClass;
$statement = Database::$connection->prepare($sql);
if(!empty($bindChar)) :
$statement->bind_param($bindChar, $bindVal);
endif;
if($statement->execute()) :
$result = $statement->get_result();
$object = $result->fetch_object();
endif;
$statement->close();
if(!empty($object)) :
return $object;
endif;
} catch(Exception $e) {
}
}
What I tried was writing an instantiation method that creates a new instance of my class, and then assign each attribute of the object the value it returns from an array from a tutorial I did. However, the tutorial was fairly outdated and didn't use any new syntax or binding, so I was trying to rework this.
Example from the tutorial below:
public static function find_by_id($id) {
global $database;
$the_result_array = static::find_by_query("SELECT * FROM " . static::$db_table . " WHERE id = $id LIMIT 1");
return !empty($the_result_array) ? array_shift($the_result_array) : false;
}
public static function find_by_query($sql) {
global $database;
$result_set = $database->query($sql);
$the_object_array = array();
while($row = mysqli_fetch_array($result_set)) {
$the_object_array[] = static::instantation($row);
}
return $the_object_array;
}
public static function instantation($the_record){
$calling_class = get_called_class();
$the_object = new $calling_class;
foreach ($the_record as $the_attribute => $value) {
if($the_object->has_the_attribute($the_attribute)) {
$the_object->$the_attribute = $value;
}
}
return $the_object;
}
private function has_the_attribute($the_attribute) {
return property_exists($this, $the_attribute);
}
What I was trying to do from the tutorial, was to return my result as an array using a while, and then assigning a variable by passing the built array into the static::instantation() method, but it doesn't seem to ever be working correctly, as any public functions I create in my calling class (Admin for example) aren't called after as they don't exist due to the Class not being instantiated.
mysqli_result::fetch_object() accepts the class name as the first argument. You can pass the class name as an argument to that method and get the instance of the model. I am not sure why you have that much code but consider my example which I wrote based on your own code:
<?php
class Model
{
public static function findByQuery(string $sql, ?string $bindChar = null, ?string $bindVal = null): ?static
{
$statement = Database::$connection->prepare($sql);
if ($bindChar) :
$statement->bind_param($bindChar, $bindVal);
endif;
$statement->execute();
$result = $statement->get_result();
return $result->fetch_object(static::class);
}
}
class User extends Model
{
private $id;
}
class Database
{
public static mysqli $connection;
}
mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);
Database::$connection = new mysqli('localhost', 'user', 'password', 'test');
$user = User::findByQuery('SELECT ? as id', 's', 'Dharman');
var_dump($user);
The output from that example is:
object(User)#4 (1) {
["id":"User":private]=>
string(7) "Dharman"
}
As you can see, the code created an instance of the class using late-static binding and it also assigned the value to a private property, which you can't do otherwise.
P.S. My example is a little bit tidier. I added parameter typing and removed a lot of unnecessary code. In particular, I remove empty try-catch which is a terrible practice.
I have now got this working, although I feel this is probably not the best way of doing it.
I'm primarily front end so please comment if there are improvements or best practices.
public static function findByQuery($sql,$bindChar = '',$bindVal = '') {
try {
$statement = Database::$connection->prepare($sql);
if(!empty($bindChar)) :
$statement->bind_param("$bindChar", $bindVal);
endif;
if($statement->execute()) :
$result = $statement->get_result();
$output = $result->fetch_object();
endif;
$statement->close();
if(!empty($output)) :
$class = get_called_class();
$object = new $class;
foreach(get_object_vars($output) as $key => $value) :
$object->$key = $value;
endforeach;
endif;
if(!empty($object)) :
return $object;
endif;
} catch(Exception $e) {
}
}
My initial thoughts were declaring an object and then I thought that the PHP fetch_object call would have just assigned my object it's properties after initiating the Class but that wasn't the case.
So what I've done is that if the statement is successful and a results object is created, I then get the object properties and values with the get_object_vars() command, and then loop through these as a key value pair, assigning each attribute it's returned value.
I can confirm this works as I can now run $admin->remove() from my removal script, as opposed to what I was having to do before which was Admin::remove($id);
I'm trying to override my constructor to create an object based on a row in my database and I'm unsure of the best way to go about it. My goal is to be able to create the object given the constructor but also have the ability to create the object from a row in my database.
Here is the pseudocode for my given scenerio:
class PurchaseOrder
{
private $id;
private $title;
private $amount;
function __construct($title, $amount)
{
$this->title = $title;
$this->amount = $amount;
}
function constructFromDB($pdo, $id)
{
$poValues = queryPO($pdo, $id); // fetches from db (psuedocode);
$this->title = $poValues->title;
$this->amount = $poValues->amount;
}
}
// Create new purchase order
$po = new PurchaseOrder("Purchase Order 1", 100);
// Query purchase order from database
$queriedPO = new PurchaseOrder()->constructFromDB($conn, 1);
But as you know, I cannot leave the constructor empty for my object to be initialized. I cannot have it be a static function as I will need to be able to manipulate the object's properties.
The constructFromDB() method can be static and return an object:
public static function constructFromDB($pdo, $id)
{
$poValues = queryPO($pdo, $id); // fetches from db (psuedocode);
$title = $poValues->title;
$amount = $poValues->amount;
$class = __CLASS__;
return new $class($title, $amount);
}
Then call it statically:
$queriedPO = PurchaseOrder::constructFromDB($conn, 1);
I have two classes. Database and Product. I successfully connected PHP with DB and I am able to print out data.
But I want to know if I am using class Product correctly? And if in future I add Product class method addProduct should I need to keep properties?
My Product class:
<?php
require_once 'DataBase.class.php';
class Product {
//Properties
// var $id;
// var $name;
// var $price;
//Methods
function __construct(){}
public function getAllProducts()
{
$db = Database::get();
$sql = "SELECT * FROM product";
$result = $db->select($sql);
return $result;
}
}
$product = new Product;
Right now it seems that I don't need properties.
I would separate the getAllProducts() function from the individual products class. Like this:
<?php
require_once 'DataBase.class.php';
function getAllProducts()
{
$db = Database::get();
$sql = "SELECT * FROM product";
$result = $db->select($sql);
return $result;
}
class Product {
// Properties:
public $sku;
public $name;
public $price;
public $size = '0';
public $weight = '0';
public $dimension = '0x0x0';
// Methods
function __construct($var1, $var2, $var3) // add or remove vars as needed
{
// use make a new product, example:
$this->sku = $var1;
$this->name = $var2;
$this->price = $var3;
// etc...
}
}
$product = new Product($var1, $var2, $var3);
// do stuff with the product
Your constructor should deal with instantiating product information for use with your database. Also, PHP is notoriously terrible for its character escape techniques. Prepared statements and typecasting will make your life easier in the long run.
want from a method return an array of objects, what is the best way
retrieving data from the db and then populate a list of objects to be returned.
<?php
class DataObject{
public function GetObjetList(){
// Connect to the database server
$dbh = new PDO("mysql:host=localhost;dbname=bookdb", "webuser", "secret");
// Execute the query return 1200 register
$stmt = $dbh->query('SELECT sku, title FROM products ORDER BY title');
while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$sku = $row['sku'];
$title = $row['title'];
return something?? --> how to??
}
}
?>
regards!
PDO already has a fetch mode that returns objects.
Change your code to this:
while ($row = $stmt->fetch(PDO::FETCH_OBJ)) {
class DataObject
{
public function __construct($pdo)
{
$this->db = $pdo;
}
public function GetObjetList()
{
$sql = 'SELECT sku, title FROM products ORDER BY title';
return $this->db->query($sql)->fetchAll(PDO::FETCH_OBJ);
}
}
Put the return after the while, not inside, use FETCH_OBJ and an array:
$rows = array();
$rows = $stmt->fetchAll(PDO::FETCH_OBJ);
return $rows;
$sql=$pardConfig->prepare("SELECT * FROM ".$this->menu); i want to call to the db table dynamically.in here it was selecting only the menu.i want to call it from object ???
<?php
$dbhost=null;
$dbname=null;
$dbuser=null;
$dbpass=null;
$file = __DIR__ ."/config.json";
$array = file_get_contents($file);
$dbConfig=json_decode($array);
$pardConfig=new PDO('mysql:host='.$dbConfig[0].';'.'dbname='.$dbConfig[1],$dbConfig[2],$dbConfig[3]);
class pardDb
{
public $config = "pard_admin_config";
public $article = "pard_article";
public $menu = "pard_menu";
public $user = "pard_user";
public $images = "pard_images";
function pardTemplate($pardConfig,$pardDbTable){
$sql=$pardConfig->prepare("SELECT * FROM ".$this->menu);
$sql->execute();
$result=$sql->fetchALL(PDO::FETCH_OBJ);
$item = array_reverse($result);
return $item;
}
}
$pardDbTable = new pardDb();
$pardDbTable->pardTemplate($config,$pardConfig);
?>
I want one object and need to call it like this ?
echo $obj->menu;
echo $obj->article;
Try refactory this in one designe patterns (start your studing by Active Record and Data Mapper) add inheritance:
http://martinfowler.com/eaaCatalog/
after see the Magic Methods __get and __set
http://php.net/manual/en/language.oop5.overloading.php#object.get