I have a custom class object in PHP named product:
final class product
{
public $id;
public $Name;
public $ProductType;
public $Category;
public $Description;
public $ProductCode;
}
When passing an object of this class to my Data Access Layer I need to cast the object passed into a type of the product class so I can speak to the properties within that function. Since type casting in PHP works only with basic types what is the best solution to cast that passed object?
final class productDAL
{
public function GetItem($id)
{
$mySqlConnection = mysql_connect('localhost', 'username', 'password');
if (!$mySqlConnection) { trigger_error('Cannot connect to MySql Server!'); return; }
mysql_select_db('databaseName');
$rs = mysql_query("SELECT * FROM tblproduct WHERE ID='$id';");
$returnObject = mysql_fetch_object($rs, 'product');
return $returnObject;
}
public function SaveItem($objectToSave, $newProduct = false)
{
$productObject = new product();
$productObject = $objectToSave;
echo($objectToSave->Name);
$objectToSave->ID;
}
}
Right now I am creating a new object cast as a type of product and then setting it equal to the object passed to the function. Is there a better way of accomplishing this task? Am I going about the wrong way?
EDITED FOR CLARITY - ADD FULL PRODCUTDAL CLASS
You don't need to cast the object, you can just use it as if it was a product.
$name = $objectToSave->Name;
I´m not sure what you are trying to achieve, but if $objectToSave is already of class product:
You can simply call $objectToSave->SaveItem() (assuming SaveItem() is part of the product class) and access it´s properties in the function like $this->Name, etc.;
In your code $productObject and $objectToSave will hold a reference to the same object.
Type casts in PHP are done like this:
$converted = (type) $from;
Note, that this won't work if the object types are not compatible (if for example $form happens to be a string or object of mismatching type).
But usual solution (called Active Record pattern, present for example in Zend Framework) is to have a base class for a database item called Row. Individual items (for example the class product from your sample) then inherit from this class.
Typical ZF scenario:
$table = new Product_Table();
$product = $table->find($productId); // load the product with $productId from DB
$product->someProperty = $newPropertyValue;
$product->Save(); // UPDATE the database
Which is IMO much better than your solution.
EDIT:
You can't cast between two unrelated objects, it is not possible.
If you want to use the DAL like this, skip the "product" object and go for simple associative array. You can enumerate over its members with foreach, unlike object's properties (you could use reflection, but that's overkill).
My recommendation: Go for the Active Record pattern (it is easy to implement with magic methods). It will save you a lot of trouble.
Currently, you are creating a new Product, then discarding it immediately (as its reference is replaced by $objectToSave.) You will need to copy its properties one by one, I regret.
foreach (get_object_vars($objectToSave) as $key => $value)
{
$product->$key = $value;
}
(If the properties of $objectToSave are private, you will need to a expose a method to_array() that calls get_object_vars($this).)
Related
So, in my framework X, let it be Phalcon, I often create models objects.
Let's assume that all fields already validated. Questions related only about creation logic.
A simple example of creating Users object and save it to DB:
<?php
$user = new Users();
$user->setName($name);
$user->setLastName($lastname);
$user->setAge($age);
$user->create();
For simplicity, I show here only 3 fields to setup, in the real world they always more.
I have 3 questions:
1) What the best way to encapsulate this logic in Factory class? If I create Factory class that will create objects like Users object, every time I will need pass long amount of parameters.
Example:
<?php
$factory = new UsersFactory();
$factory->make($name, $lastname, $address, $phone, $status, $active);
2) Even if I implement Factory in a way showed above - should Factory insert data in DB? In my example call method create()? Or just perform all setters operations?
3) And even more, what if i will need to create Users objects with relations, with other related objects?
Thank you for any suggestions.
Your question starts out simple and then builds with complexity. Reading your post it sounds like your concerned about the number of arguments you would have to pass to the method to build the object. This is a reasonable fear as you should try to avoid functions which take more than 2 or 3 args, and because sometimes you will need to pass the 1st 3rd and 5th arg but not the 2nd and 4th which just gets uncomfortable.
I would instead encourage you to look at the builder pattern.
In the end it will not be that much different than just using your User object directly however it will help you prevent having a User object in an invalid state ( required fields not set )
1) What the best way to encapsulate this logic in Factory class? If I create Factory class that will create objects like Users object, every time I will need pass long amount of parameters.
This is why I recommended the builder pattern. To avoid passing a large number of params to a single function. It also would allow you to validate state in the build method and handle or throw exceptions.
class UserBuilder {
protected $data = [];
public static function named($fname, $lname) {
$b = new static;
return $b
->withFirstName($fname)
->withLastName($lname);
}
public function withFirstName($fname) {
$this->data['first_name'] = $fname;
return $this;
}
public function withFirstName($lname) {
$this->data['last_name'] = $lname;
return $this;
}
public function withAge($age) {
$this->data['age'] = $age;
return $this;
}
public function build() {
$this->validate();
$d = $this->data;
$u = new User;
$u->setFirstName($d['first_name']);
$u->setLastName($d['last_name']);
$u->setAge($d['age']);
return $u;
}
protected function validate() {
$d = $this->data;
if (empty($d['age'])) {
throw new Exception('age is required');
}
}
}
then you just do..
$user = UserBuilder::named('John','Doe')->withAge(32);
now instead of the number of function arguments growing with each param, the number of methods grows.
2) Even if I implement Factory in a way showed above - should Factory insert data in DB? In my example call method create()? Or just perform all setters operations?
no it should not insert. it should just help you build the object, not assume what your going to do with it. You may release that once you build it you will want to do something else with it before insert.
3) And even more, what if i will need to create Users objects with relations, with other related objects?
In Phalcon those relationships are part of the entity. You can see in their docs this example:
// Create an artist
$artist = new Artists();
$artist->name = 'Shinichi Osawa';
$artist->country = 'Japan';
// Create an album
$album = new Albums();
$album->name = 'The One';
$album->artist = $artist; // Assign the artist
$album->year = 2008;
// Save both records
$album->save();
So to relate this back to your user example, suppose you wanted to store address information on the user but the addresses are stored in a different table. The builder could expose methods to define the address and the build method would create both entities together and return the built User object which has a reference to the Address object inside it because of how Phalcon models work.
I don't think it's entirely necessary to use a builder or "pattern" to dynamically populate your model properties. Though it is subjective to what you're after.
You can populate models through the constructor like this
$user = new Users([
'name' => $name,
'lastName' => $lastname,
'age' => $age,
]);
$user->create();
This way you can dynamically populate your model by building the array instead of numerous method calls.
It's also worth noting that if you want to use "setters" and "getter" methods you should define the properties as protected. The reason for this is because Phalcon will automatically call the set/get methods if they exist when you assign a value to the protected property.
For example:
class User extends \Phalcon\Mvc\Model
{
protected $name;
public function setName(string $name): void
{
$this->name = $name;
}
public function getName(): string
{
return $this->name;
}
}
$user= new MyModel();
$user->name = 'Cameron'; // This will invoke User::setName
echo $user->name; // This will invoke User::getName
It is also worth noting that the properties will behave as you'd expect a protected property to behave the same as a traditional protected property if the respective method is missing. For example, you cannot assign a value to a protected model property without a setter method.
I'm writing a method that copies an object. Instead of manually setting each property manually, it would be more robust to just loop over the original object's properties...
//Booo
$new->name = $old->name;
$new->color = $old->color;
...
//Oh yeah...
foreach ($old as $prop=>$val){
$new->$prop = $val;
}
unset $new->id;
It appears that CakePHP entities cannot be iterated over in this way. I tried using $old->toArray(), which basically works... but has the drawback of converting all the associations to arrays also, which is screwing this up for me down stream.
How do I loop over the $old properties without converting all the data types?
Update:
Mark brought to my attention the existence of a __clone() method. Sounds like it does exactly what I need but I'm still figuring out how to use it.
You can use $entity->visualProperties()
foreach($old->visualProperties() as $property) {
if($new->has($property))
$new->set($property, $old->get($property));
After looking at this for a while, and discovering there is no __clone() function for entities, at least in 3.8, I have worked out how to do it, with the hint from DouglasSantos :
//Find out the entity classname
$classname = get_class($entity);
//Instanciate a new object of that class
$clone = new $classname;
//Use visibleProperties to clone it
foreach($entity->visibleProperties() as $property)
if($clone->has($property))
$clone->set($property, $entity->get($property));
Of course you could combine the first 2 lines into one line, but I have split it out for clarity.
UPDATE: I have discovered if you use the has->($property) check it will skip many of the fields. So the corrected answer is :
//Find out the entity classname
$classname = get_class($entity);
//Instanciate a new object of that class
$clone = new $classname;
//Use visibleProperties to clone it
foreach($entity->visibleProperties() as $property)
$clone->$property = $entity->$property;
It is actually much easier to use the Table Object:
// Assuming your model is called "Documents"
// If you are in the Controller, you can just use `$this->Documents`
instead of fetching the Table from the Registry
use Cake\ORM\TableRegistry;
$table = TableRegistry::getTableLocator()->get('Documents');
// newEntity() creates a new Entity from an array of data
$documentCopy = $table->newEntity(
// extract() extracts the given properties as an associative array
$document->extract(
// getVisible() will get all visible properties as an array
$document->getVisible()
)
);
Codeigniter can return a database query as generic "Object" like:
$q = $this->db->get("some_table");
$obj = $this->q->row();
$var = $obj->some_property
In my case I want to make a PHP class who's public variables are 1 for 1 with the database columns, along with some public methods. Is there a quick one-shot way to cast or convert the generic "Row" object into my custom class object? I've read posts that hint that it is certainly possible, but most involve a really hacky serialize/deserialize solution. In the past I have just done:
public function __construct($row) {
$this->prop = $row->prop;
$this->id = $row->id;
$this->value = $row->value;
}
And I find this is very tedious and makes ugly code.
See the third section under result():
CodeIgniter User Guide: Generating Query Results
You can also pass a string to result() which represents a class to instantiate for each result object (note: this class must be loaded)
$query = $this->db->query("SELECT * FROM users;");
foreach ($query->result('User') as $row)
{
echo $row->name; // call attributes
echo $row->reverse_name(); // or methods defined on the 'User' class
}
When using nested objects (ObjTwo as a property of objOne):
$objOne->property = new ObjTwo($objOne);
What's the best way to communicate? Here are a few methods I can think of:
Using specific get/set methods
class ObjTwo {
__construct($objOne){
$prop1 = $objOne->get_prop1();
// do something with prop1
$prop2 = $objOne->get_prop2();
// do something with prop2
// ... Having to write all these out is kind of a pain
// if you're going to have 20+ vars, and there's no
// easy way to loop through them.
}
}
The problem: Writing these out line by line, and having to update it when I add new properties.
I know that having a get/set method for each property is recommended, however I'd really like to loop through the data...
How about get_object_vars()
class ObjTwo {
__construct($objOne){
extract(get_object_vars($objOne));
// do something with the vars
}
}
The problem: This method bypasses the ability to use getter/setter methods, and each property would have to be public to be accessible.
Dynamic getter/setter method calls
Another way I have considered is to create an array of fields, and have a strict policy of naming the getter/setter methods:
class ObjTwo {
__construct($objOne){
$prop_array = array('prop1', 'prop2', 'prop_three');
$values = array();
foreach ($prop_array as $prop){
$values[$prop] = $objOne->get_{$prop}();
}
}
}
The problem: Every time I add a new property, I have to make sure to name the get_method() correctly, and update the $prop_array.
Anyone have any better solutions? Maybe just building an array of data?:
$objOne->property = new ObjTwo($objOne->get_data());
I like this solution
Having thought this through, here's a little clarification: I'm not trying to just make identical copies from parent to child or vice-versa - I edited the above examples to show that a little better. It's more just the idea of passing a subset of the object's data from one place to another.
Instead of having to write:
$first_name = $this->member->get_first_name();
$last_name = $this->member->get_last_name();
$email = $this->member->get_email();
$display_name = $this->member->get_display_name();
// etc... and
$this->member->set_first_name($first_name);
$this->member->set_last_name($last_name);
$this->member->set_email($email);
$this->member->set_display_name($display_name);
// etc..
How about having a $this->member->get_fields('first_name', 'last_name', 'email', 'display_name'); method? I don't like having to remember the field names exactly (fname, f_name, first_name, etc), so you could use class constants:
$data = $this->member->get_fields(array(
Member::FIRST_NAME, Member::LAST_NAME, Member::EMAIL, Member::DISPLAY_NAME
));
This way, I can loop through the returned data.
foreach ($data as $key=>$value) // ...
And setting the fields...
$this->member->set_fields(array(
Member::FIRST_NAME => $first_name, // THE BIG ADVANTAGE HERE:
Member::LAST_NAME => $last_name, // These field keys auto-complete
Member::EMAIL => $email, // so you don't have to remember them!
Member::DISPLAY_NAME => $display_name,
// etc...
));
Still thinking this through... any thoughts?
I think you're asking the wrong question. Furthermore I think it would only be possible to really help, if you provided a real example instead of those pseudo examples. Every real situation is different with regard to the proper solution.
Generally all your proposals smell. It seems that what you need is not injection but inheritance. If your 'child' class really needs access to all or most of the properties of another class, it seems it should extend that class.
The parts of your software should know as little as possible about each other. In your comment you mention that you have a Member class and a Form class. I don't know why any of them should know anything about the other at all.
Furthermore you seem to be under the impression that you need to map every property to a property in the new class. Why? If you pass an instance of a class into another class via custructor (= dependency injection) then you can map that instance to a property and then access all properties of the injected instance via that instance. No mapping needed.
class Consumer
{
private $injectedClass;
function __construct($injectedClass)
{
$this->injectedClass = $injectedClass;
}
public function someFunction()
{
//do something by using any property of the injected class
$this->injectedClass->getProperty();
}
}
I tend to do it like this. This may not be the best way to do it:
class Parent_Obj {
$var1; // explanation
$var2; // explanation
$var3; // explanation
$child_obj; // explanation
__construction() {
/* Do a bunch of stuff */
$this->$child_obj = new Child_Obj ($this);
}
}
class Child_Obj {
$var1; // explanation
$var2; // explanation
$var3; // explanation
$parent_obj; // explanation
__construction($parent) {
/* Do a bunch of stuff */
$this->$parent_obj = $parent;
}
/* Some function that needs a method or property of the parent object */
function some_function () {
/* do some stuff */
echo $this->parent_obj->var1; // echo a property of the parent obj
}
}
I believe the term for this is called "aggregation".
I've used php enough to be quite comfortable with it, but recently I've been looking through some MVC frameworks to try and understand how they work, and I've come across a syntax and data structure which I haven't encountered before:
function view($id)
{
$this->Note->id = $id;
}
What is the ->id section of this code? Is this a sub-method based off it's parent method? If so, how do I go about writing code to create such a structure? (ie. creating the structure from scratch, not using an existing framework like the above example from cakephp).
The following code demonstrates how one could arrive at the structure you described.
<?php
class Note
{
public $id = 42;
}
class MyClass
{
public function __construct() {
// instance of 'Note' as a property of 'MyClass'
$this->Note = new Note();
}
public function test() {
printf("The \$id property in our instance of 'Note' is: %d\n",
$this->Note->id);
}
}
$mc = new MyClass();
$mc->test();
?>
Note is a property of $this and it's (current) value is an object with a property named id which gets assigned the value of $id.
If id was a method of the Note object, the line would read $this->Note->id($id);.
Another way to think about the construct is considering
$this->Note->id = $id;
similar to
$this["Note"]["id"] = $id;
Which would actually be equivalent if both objects ($this and subobject Note) were based on ArrayAccess.