Okay, here is the general idea (there is a lot of work I didn't do, such as establishing a real connection or a lot of validation/refactoring for efficiency type stuff. Don't focus on the fact that the methods/functions are static (that was just to reduce my coding a slight bit).
In essence, your Objects are more like DTOs (Data Transfer Objects). They may contain some useful utility functions for the item, but for the most part they are just a way to transfer that data from a controller to a view, or whatever path you may need to take.
Objects:
PHP Code:
<?php
namespace Objects;
class Product
{
private $productId;
public function GetProductId()
{
return $this->productId;
}
public function SetProductId($value)
{
if (is_int($value))
{
$this->productId = $value;
}
}
private $name;
public function GetName()
{
return $this->name;
}
public function SetName($value)
{
$this->name = $value;
}
private $supplier;
public function GetSupplier()
{
return $this->supplier;
}
public function SetSupplier($value)
{
$this->supplier = $value;
}
private $accessories;
public function GetAccessories()
{
return $this->accessories;
}
public function SetAccessories($value)
{
$this->accessories = $value;
}
public function AddAccessory($accessoryId, $accessoryName)
{
if (!is_array($this->accessories))
{
$this->accessories = array();
}
$this->accessories[] = new Accessory($accessoryId, $accessoryName);
}
}
class Accessory
{
public $accessory_id;
public $name;
public function __construct($accessory_id, $name)
{
$this->accessory_id = $accessory_id;
$this->name = $name;
}
}
class Supplier
{
public $supplier_id;
public $name;
public function __construct($supplier_id, $name)
{
$this->supplier_id = $supplier_id;
$this->name = $name;
}
}
?>
Business Layer: (you will notice I am constantly overwriting the product id, name, supplier id and name, this is because I was lazy in my example)
PHP Code:
<?php
namespace Business;
class Product
{
public static function GetProductInfoAndAccessories($productId)
{
if (is_int($productId))
{
$results = \DataAccess\Product::GetProductInfoAndAccessories($productId);
if ($results != null)
{
// process results into object
$product = new \Objects\Product();
foreach ($results as $row)
{
$product->SetProductId($row['product_id']);
$product->SetName($row['product_name']);
$product->AddAccessory($row['accessory_id'], $row['accessory_name']);
}
return $product;
}
return null; // or throw an exception
}
else
{
throw new Exception("Must provide a valid product id");
}
}
public static function GetProductInfoAccessoriesAndSupplier($productId)
{
if (is_int($productId))
{
$results = \DataAccess\Product::GetProductInfoAccessoriesAndSupplier($productId);
if ($results != null)
{
// process results into object
$product = new \Objects\Product();
foreach ($results as $row)
{
$product->SetProductId($row['product_id']);
$product->SetName($row['product_name']);
$product->AddAccessory($row['accessory_id'], $row['accessory_name']);
$product->SetSupplier(new \Objects\Supplier($row['supplier_id'], $row['supplier_name']));
}
return $product;
}
return null; // or throw an exception
}
else
{
throw new Exception("Must provide a valid product id");
}
}
}
?>
Data Access: (the Base would typically have a Close function as well to destroy/unset the connection variable)
PHP Code:
<?php
namespace DataAccess;
class Product extends Base
{
public static function GetProductInfoAndAccessories($productId)
{
self::GetConnection()->prepare("SELECT p.product_id, p.name AS product_name, a.accessory_id, a.name AS accessory_name
FROM Products AS p LEFT JOIN Accessories AS A ON p.product_id = a.product_id WHERE p.product_id = ?");
return self::GetConnection()->execute(array($productId));
}
public static function GetProductInfoAccessoriesAndSupplier($productId)
{
self::GetConnection()->prepare("SELECT p.product_id, p.name AS product_name, a.accessory_id, a.name AS accessory_name, s.supplier_id, s.name AS supplier_name
FROM Products AS p LEFT JOIN Accessories AS A ON p.product_id = a.product_id LEFT JOIN Suppliers AS S on p.product_id = s.product_id WHERE p.product_id = ?");
return self::GetConnection()->execute(array($productId));
}
}
class Base
{
private static $connection;
public static function GetConnection()
{
if (self::$connection === null)
{
self::$connection = ... // define a new connection
}
return self::$connection;
}
}
?>
Page needing Product and Accessories (don't forget, Business\Product validates/filters the $_GET item
PHP Code:
$productInfo = \Business\Product::GetProductInfoAndAccessories($_GET['product_id']);
// Do whatever you need to do with $productInfo; pass it to your view, whatever, it is your DTO
Page needing Product, Accessories, and Suppliers
PHP Code:
$productInfo = \Business\Product::GetProductInfoAccessoriesAndSuppliers($_GET['product_id']);
// Do whatever you need to do with $productInfo; pass it to your view, whatever, it is your DTO
Again, not saying this is a right or wrong way, just a different approach that can/did work well for the applications we maintained at my old job.
Bookmarks