How to implement PDO FETCH_CLASS in correct way? - php

Hi world genius of programming. I am quite newbie in PDO and OOP, Please understand.
I try to do the most simple thing in the world - get data from a table in MySQL.
I want to:
1) SELECT * from ... it's about 20 fields.
2) To get an array of object with 4-6 of properties.
3) I want to use fetchAll and FETCH_CLASS...
PDOStatement PDO::query ( string $statement , int $PDO::FETCH_CLASS , string $classname , array $ctorargs )
I've found that we can pass an array of argument but can't implement it.
So what am I doing?
class handler{
connection etc..
public $params = array('surname','id','country','display' );
return $stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'person',$this->params);
class person {
public $surname=null;
public $id=null;
public $country=null;
public $status=null;
and then
__construct ()
i will not put it - cause i ve got 50 variants of them(((
}
So, I need to filter options from 20 fields fetching a class but not in SELECT mode instead of *...
Is it possible?
I know that you are genius!
Forgive for newbieness
UPDATE
function __construct($surname,$id,$country,$display) {
$this->surname=$surname;
$this->country=$country;
$id->id->$id
// that the only i need in this oblject
}
function __construct() {
$arg=array('surname','id');
foreach ($arg as $val) {
$this->{$val}=$$val;
}
}
it seems it maybe the next.. not construct function that will filter properties...
UPDATE
I tried solutions as #GolezTrol kindly proposed.
Solution 1 is arguing for... Notice: Undefined property: Person::$_attributes in
if i make
class Entity {
public $_attributes;
function __construct() { ....
or
class Person extends Entity {
public $_attributes;
}
it works.. but i get an object...
[0] => Person Object
(
[_attributes] => Array
(
[0] => surname
[1] => id
[2] => country
[3] => status
)
[id] => 298
.. it's not good(

I think you mean that you want to load only the properties that you specified instead of all values that were returned from the query. Your attempt is to do that by passing the desired field names to the constructor.
Solution 1: Just specify the array of properties and block the rest
Your way might just work, if you get a little help from the __set magic method. Using func_get_args() you can get all the arguments of a function (the constructor in this case) into an array. This way, you get the array of field names that you passed to fetch_all.
The magic setter only sets the properties if they exist in the array that was given to the constructor, so essentially it filters out all fields you don't want.
Advantage: easy. No specific implementation needed in descendant classes. You could just use Entity as a class for all entities.
Disadvantage: magic setter is called for every property and calls in_array this may be slow. fetch_all is determining which fields to read, while maybe this should be the class's responsibility.
class Entity {
function __construct() {
$this->_attributes = func_get_args();
}
function __set($prop, $value) {
if (in_array($prop, $this->_attributes)) {
$this->$prop = $value;
}
}
}
// If you would need a descendant class to introduce methods, you can..
class Person extends Entity {
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person', array('id', 'surname', 'gender'))
Solution 2: block all properties that don't exist
Similar solution, but much cleaner, I think. Implement the magic setter and make it do... nothing. It will be called for properties that don't exist and only for properties that don't exist. So in Person you just declare whatever values you want to read. All other properties will be directed to the empty __set method so they are implicitly ignored.
Advantage: Still easy. Hardly any implementation. You can put the empty method in a base class or just implement it in Person and every other class you have. You just declare the properties in Person. You don't even need to specify the fields you want to read in fetch_all. Also, reading into existing properties is faster.
Disadvantage: if you want to read different sets of information into the same class, this is not possible. The person in my example below always has an id, surname and gender. If you want to read for instance id only, you have to introduce another class. But would you want that?..
class Entity {
function __set($prop, $value) {
// Ignore any property that is not declared in the descendant class.
}
}
class Person extends Entity {
public $id = null;
public $surname = null;
public $gender = null;
}
$stmt->fetchAll(PDO::FETCH_CLASS | PDO::FETCH_PROPS_LATE, 'Person')
Solution 3: Read only the fields you want
This is actually the best solution. Instead of selecting all fields, SELECT *, select only the fields you want to have: SELECT id, surname, gender ... This way, you won't have objects with too many values, but more importantly, you also decrease the load on your database. The database doesn't need to fetch the data, PHP doesn't need to receive it, and if the database server is separate from the webserver, you also save network traffic. So in all regards, I think this is the best option.

Related

static properites does not exist into the object

class SubObject
{
static $static_a= 0;
public $normal_a=0;
public function __construct() {
++$this->normal_a;
++self::$static_a;
}
}
$obj1 = new SubObject();
print_r($obj1);
result is :
SubObject Object
(
[normal_a] => 1
)
My question is that why its not display output as:
SubObject Object
(
[normal_a] => 1
[static_a] => 1
)
Does static properites does not exist into the object ? Static variable or property are the way to preserver value of the variable within the context of different instance?
The static properties are attributes of the class (all instances), not an attribute of a specific instance. Here's another class ...
class Dog {
public static $species = 'mammal';
public $furColour;
public function __construct($furColour) {
$this->furColour = $furColour;
}
}
$myDog = new Dog('brown');
All dogs are mammals, in other words the entire "class" of dogs are mammals, so it makes sense to store the $species attribute at the class level (not in every instance of the class). Not all dogs have the same fur colour, that is an attribute of a specific instance of the class know as "Dog".
So, as decided by whoever designed the print_r function, it only prints attributes specific to the instance, not all the attributes of the entire class (or set of all instances). This design decision makes sense. Especially for classes that, for example, define 10's or even 100's of attributes to be used a constants: you don't want to see all these every time you print_r to debug.
FYI, if your app has a real need to get the static values, I think this works
print_r( (new ReflectionClass('SubObject'))->getStaticProperties() );
SubObject Object
(
[normal_a] => 1
[static_a] => 1
)
normal_a and static a are properties.when you dump an object it returns properties and their values.

General PHP/OOP Strategy - How to communicate between nested objects

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".

PHP custom object casting

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).)

issue about selecting objects in an inheritance context in propel-symfony

I have an issue that is quite annoying with symfony 1.2 and propel.
I have a model where I have implemented inheritance using the single-table strategy. So, here is an excerpt of my model:
Ad (id, posted_date, description)
then RealEstateAd(location, price, transaction_type) and JobAd(position, requirements, company) which inherit both from Ad.
I would like to display all ads, but I would like to display a RealEstateAd differently from a JobAd. To achieve this, I've used a partial for a RealEstateAd and a partial for a JobAd.
So, in the action, I did this:
$c = new Criteria();
$this->allAds = AdPeer::doSelect($c);
In the template, I check the class of each object:
$add = $allAds[$i];
if ($add instanceof RealEstateAdd)
//Use the RealEstatePartial
The problem is that class of an object in the $allAds array is sfOutputEscaperObjectDecorator.
So, nothing is displayed at all.
How could I deal with this issue? is there a way to get an array with objects which are actually of the class RealEstateAd or JobAd? How is the hydrating process carried out here?
sfOutputEscaperObjectDecorator has a raw method to get the undelying object.
Anyway, the best thing you can do is to have three different classes (i assume that real estates and job ads are Models)
class Ad { public function __toString() { print 'ad'; } }
class RealEstates extends Ad { public function __toString() { print 'realad'; } }
class JobAd extends Ad { public function __toString() { print 'jobad'; } }
so you can just call print $myAd; in your view without checking the object types.
(use polymorphism luke)
I don't know much about symfony or propel, so if i'm way off base here i apologize and just ignore this post...
What if you create a helper function getAdType() that uses some methodology to distinguish between the different types of ads.
function getAdType( $ad ) {
if ( isset( $ad->position ) ) {
return 'job';
}
elseif ( isset( $ad->transaction_type ) ) {
return 'realestate';
}
}
$add = $allAds[$i];
if ( getAdType( $add ) == 'realestate' )
//Use the RealEstatePartial
I might be misunderstanding something, but unless you have overloaded AdPeer::doSelect(), then it will only return an array of instance of Ad.
If you were to post your schema, it would be easier for me or others to help as it is not really clear how you've built your object model. Is RealEstateAd a propel class defined in schema.yml? or is it a custom class you've added to lib?
Eitherway, AdPeer::doSelect* will only return Ad, so it sounds like what you need is a custom retriever in the AdPeer. Again, more info about your schema will help.

MVC model where to put data specific checks

I'm writing my first application with Zendframework.
My question is about the Model–View–Controller (MVC) architectural pattern.
I currently have a model with refer to a database table.
Here's the classes that I currently have :
Model_Person
Model_PersonMapper
Model_DbTable_Person
Now, I see a lot of examples on the net, but all of them are simple cases of insert/update/delete.
In my situation, I have to check if a person exists, and if it doesn't, I have to insert it and retrieve the ID (I know save return the Id, but it's not exactly what I have to do, this is and example).
It's quit simple, but I want to know where to put the database logic for all the others specific cases. Some others cases might involve checks across other tables or ... whatever !
Should I add all the specific functions in my Model_XXXXMapper with something that would be very specific with the current validation/process that I want to do? like a function getIdOfThePersonByNameOrInsertIfNotExists() (sample name of course!!!)
Or should it reside in the controller with some less specifics access to my model would be validated?
In other word, where do I put all the data specifics functions or check ?
I think the real work should occur in your model objects, not in the controller. Any selects/creates that start with the person table would be in the DbTable_Person object, things like:
// DbTable_Person
// returns sets of or single Person objects
public function createByName( $name ) // perhaps throws exception if name already exists
public function findById( $id )
public function findByName( $name )
public function findHavingAccount( $account_id ) // references another table
// controller
// with your example, like what Galen said,
// I would let the controller handle this logic
$person = $person_table->findByName($name);
if ( !$person ) {
$person = $person_table->createByName($name);
}
if ( !$person ) { throw new Zend_Exception('huh?'); }
$id = $person->id; // you wanted the ID
I would definitely split the function up into search/create functions.
Here's a basic implementation...
$personTG = new Model_PersonTableGateway;
if ( !$person = $personTG->findByName( $name ) ) {
$person = new Model_Person;
$person->name = $name;
// other variables
$newPersonId = $personTG->create( $person ); // creates a new person
}
I use table gateway. You can substitute your class for the TG.
You can have the create() function return just the id of the newly created person, or the entire person...it's up to you.
You might be interested in Zend_Validate_Db_NoRecordExists and its sister. If you are using Zend_Form you can add this validator to your form element. Many folks use Zend_Form to validate and filter data before they reach the domain model.
If you are not using Zend_Form, you can simply use this validation class in your service layer. A simple service class could be something like
`
class Service_Person_Validate
{
public function creatable($data)
{ // return true|false
}
}

Categories