I'm using Doctrine 1.2. I'd like to execute a Doctrine_Query that, instead of returning a Doctrine_Collection will return a class of my choosing. That is, something like
$o = Doctrine_Query::create()
->from('Foo')
->execute();
$o; //instance of Doctrine_Collection
will normally return a generic Doctrine_Collection object. Instead I'd like it to return a Foo_Collection object, which I define elsewhere
class Foo_Collection extends Doctrine_Collection
{
public function soSomethingSpecificToAFooObject()
{
}
}
which will allow me to logically group functionality.
Is this possible? From my reading and poking at the code base this would seem to have something to do with hydrators, but I haven't been able to a manual page or tutorial that covers what I'm after.
Im pretty sure you can just add the following to your Record's setUp or construct methods (the table should be available in either one construct is run before setUp i think though):
$this->_table->setAttribute(Doctrine_Core::ATTR_COLLECTION_CLASS, 'Foo_Collection');
You can also set this globally on the Doctrine_Connection if you needed to extend Doctrine_Collection and use a different class throughout all models.
Related
I have built a small PHP MVC framework and just want to clarify the best way to get data from one model into another. For example:
I have a Users_model that contains a method called get_users().
I also have Communications_model that needs to get specific or all user data and as such needs to access the get_users() method from the Users_model.
Is it best practice to:
a) Instantiate the Users_model in a controller and pass the data from the get_users() method into the Communications_model?
b) Instantiate the Users_model inside the Communications_model and run get_users() from there, so it can be accessed directly?
c) Another way?
Many thanks for any help.
It depends of your motive behind this.
If you want effect on result, then using well know library, like Doctrine etc. should be your choice.
If you want to learn design patterns, then you should get read about ActiveRecord or DataMapper + Repository patterns. Then implements both and check out.
If you want your code, this way - ORM should represent relations of data, then you should ask what it more important? If you menage communication (bus, train), then user can be there assigned and getting users from communication is OK. If user have communication (like car), then relation is reversed.
All depends, what is you motive behind this. Using library, like Doctrine, could you help you running you application. If you want learn design patterns, then check out both options to get some experience.
What you call "users model" is a repository. And what you call "communication model" looks like a service.
Your communication service should have the user repository passed in constructor as a dependency.
I honestly think, that a huge part of your confusion is that you try to call all of those things "models". Those classes are not part of the same layer. You migth find this answer to be useful.
All are possible ways but what I usually do is, whenever there is any function that I think would be reused a number of times by a number of objects, I declare it as static.
It would save the effort of playing with object declaration and would be easily accessible by ClassName::function();
Again, it's a design choice, usually objects are declared right there in the controller and used as per the need but just to save declaration of objects again and again I follow the approach of declaring function static.
The simple principle here is using the __construct() (constructor) to build the object with the relevant properties from the Database. The User Model will have a static function (therefore accessible through any scope) to create an array of instanced objects by simply passing the model data through a new self() which returns the instance.
The concept is you end up with an array of User_Model instances each being a build of the Database columns to properties. All that's left is to create the Database Model and the functions to retrieve the columns and data.
class Communications_Model {
private $_all_users;
public function getUsers() {
$this->_all_users = Users_Model::loadAllUsers();
}
}
class Users_Model {
private $_example_property;
public function __construct($user_id) {
$data = SomeDatabaseModel::getConnection()->loadUserFromDatabase((int)$user_id);
$this->_example_property = $data['example_column'];
}
public static function loadAllUsers() {
$users = array();
foreach(SomeDataModel::getConnection()->loadAllUsers() as $data) {
$users[] = new self($data['user_id']);
}
return $users;
}
}
Of course, now, you have a $_all_users; property that has an array of instanced User Models containing the data.
I would know why many people use $users = DB::table('users')->get(); instead $users = Users::all(); in Laravel projects ? What is reason ?
Regards
You can do this because Model and the DB facade both implement functions that yield a Builder instance.
https://laravel.com/api/5.2/Illuminate/Database/Eloquent/Model.html
https://laravel.com/api/5.2/Illuminate/Database/Query/Builder.html
The difference is, instances of Model have properties which set up a Builder with predesignated information, like table, and also provide it with events, relationship information, specific static bindings, and a bunch of other handy helpers that constrain to objects and make object-oriented programming easier.
So yes, you can use a model and then take the query Builder object and change its table (just like you can change anything else about a Builder), but it's fighting a system specifically designed to make query building easier.
At heart, what Laravel does is take the Symfony2 framework and streamline it so everything is simpler. Models are one such instance of this.
From the Laravel
public static function all()
{
$input = array_merge(static::get(), static::query(), static::file());
// ....
return $input;
}
So all() calls get() and returns it's contents along with query(), and file() the $_FILES superglobal.
Preference will obviously depend on circumstance. I personally choose to use Input::get($key, $default) as I usually know what I am after.
I have class:
class item{
public id='';
public name='';
}
inside this class i want to have a function that fills up class with values from mysql query
like this:
$result_item = $this->mysqli->query("SELECT *
FROM items
WHERE item_id=".$item_id."
LIMIT 1");
$res = $result_item->fetch_object(SalesOrderItem);
$this = $res;
this code doesnt work, but is there a way to do this?
You need to look at the documentation around the mysqli::fetch_object.
Your class name needs to be specified as a string like so:
$result_item->fetch_object('SalesOrderItem'); // or 'item' your question is inconsistent here
You also may need to pass some values to the constructor to help you along. I would strongly recommend reading through the user notes on the documentation page - http://us3.php.net/manual/en/mysqli-result.fetch-object.php for some better examples of usage than given in the main documentation itself.
The fatal error you mention in your comments is because you can't change $this. That is an internal reference to the current object instance. Trying to change it make no sense.
If you intent is you have an object class that is, in essence, its own object relational mapper (ORM). To where it makes a call to the database, populates properties from records and somehow mutates itself into another class, this is not really possible. What you probably need to look to do is utilize a factory pattern of sorts to have a class that does nothing but instantiate classes of given type using the ORM approach.
So maybe usage would be like this:
// The class with MySQLi logic could be called something like MysqlObjectfactory
// It could take input like an instantiated mysqli object, DB table name,
// the class name you are trying to map to, and the id for the specific item in the class you are looking for
// it would use the logic noted above to generate an object with the specifications given
// and return it to the caller
$object = MysqliObjectFactory::getObject($mysqli, $db_table, $class_name, $id);
The other thought that jump to my mind is: why reinvent the wheel? It sounds like what you are looking for is an object relational mapper. There are several of these for PHP that are really widely used: Doctrine, Propel, PHP Active Record, etc. You might check these out as they will give you a lot more functionalitu/flexibility than trying to do this with mysqli::fetch_object() where the mapping depends on the database field (or provided alias in SQL) exactly matching the class property names (that is without having to do mapping in class constructor).
Example...
Person - fields of the table:
id_person
name
Now, let's suppose I have the model $person in my code. I would like that everytime was called $person->name='TheName' Yii called the my customized function $person->setName('TheName'), enforcing the setter.
Is there a way to accomplish that?
I tryed to make the model's attributes protected/private but it does not work. Yii seems only to call the setter/getter AFTER to check if the attribute exists at the table. When the attribute exists, yii set it and no setter is called.
Thanks in advance.
UPDATE: The reason is that I have already so many use of $model->attribX in a system but now I need to implement someway to trigge some 'chained' update depending on $model->attribX is changed and I dont want to change all of '$model->attribX' by something like '$model->changeAttribX(...)';
Yii's implementation of __get and __set in CActiveRecord is different than the "standard" one in CComponent; the latter checks for (and prefers to use) a getter and a setter for the property, while the former does not do this at all.
To directly answer your question: you would need to build this functionality into your own class having the two implementations mentioned above as a guide, e.g. somewhat like this for the setter:
public function setAttribute($name,$value)
{
$setter='set'.$name;
if(method_exists($this,$setter))
$this->$setter($value);
else if(property_exists($this,$name))
$this->$name=$value;
else if(isset($this->getMetaData()->columns[$name]))
$this->_attributes[$name]=$value;
else
return false;
return true;
}
This implementation gives precedence to getters and setters over bare properties, which may or may not be what you want. After subclassing CActiveRecord like this, you would derive your own models from the subclass.
Important consideration: All the same, you do not say what you want to achieve using this functionality and this raises questions. For example, usually features like this are used to validate values, but Yii has its own validation system in place. It is possible that there is a better (more Yii-like) way to do what you want.
What i get from your question is - "I want to do some stuff before the field is saved in the database". If that is the question, you can override the beforeSave() method.
public function beforeSave() {
if (count($this->name) > 100)
echo "how come your name is so big?";
return parent::beforeSave();
}
Just starting to work with Doctrine2, and am wondering how/if I can use a custom collection class. Searches point me to this part of the documentation:
Collection-valued persistent fields and properties must be defined in terms of the Doctrine\Common\Collections\Collection interface. The collection implementation type may be used by the application to initialize fields or properties before the entity is made persistent. Once the entity becomes managed (or detached), subsequent access must be through the interface type.
While I'm sure that's crystal clear to someone, I'm a little fuzzy on it.
If I setup my Entity to initialize (say in __construct()) the collection variable to a class that implements the correct interface - will Doctrine2 continue to use that class as the collection? Am I understanding that correctly?
Update: Also, I gather from various threads that the placeholder object used in lazy loading may influence how a custom collection can be used.
Let me try to clarify what is possible, not possible and planned with examples.
The quote from the manual basically means you could have the following custom implementation type:
use Doctrine\Common\Collections\Collection;
// MyCollection is the "implementation type"
class MyCollection implements Collection {
// ... interface implementation
// This is not on the Collection interface
public function myCustomMethod() { ... }
}
Now you could use it as follows:
class MyEntity {
private $items;
public function __construct() {
$this->items = new MyCollection;
}
// ... accessors/mutators ...
}
$e = new MyEntity;
$e->getItems()->add(new Item);
$e->getItems()->add(new Item);
$e->getItems()->myCustomMethod(); // calling method on implementation type
// $em instanceof EntityManager
$em->persist($e);
// from now on $e->getItems() may only be used through the interface type
In other words, as long as an entity is NEW (not MANAGED, DETACHED or REMOVED) you are free to use the concrete implementation type of collections, even if its not pretty. If it is not NEW, you must access only the interface type (and ideally type-hint on it). That means the implementation type does not really matter. When a persistent MyEntity instance is retrieved from the database, it will not use a MyCollection (constructors are not invoked by Doctrine, ever, since Doctrine only reconstitutes already existing/persistent objects, it never creates "new" ones). And since such an entity is MANAGED, access must happen through the interface type anyways.
Now to what is planned. The more beautiful way to have custom collections is to also have a custom interface type, say IMyCollection and MyCollection as the implementation type. Then, to make it work perfectly with the Doctrine 2 persistence services you would need to implement a custom PersistentCollection implementation, say, MyPersistentCollection which looks like this:
class MyPersistentCollection implements IMyCollection {
// ...
}
Then you would tell Doctrine in the mapping to use the MyPersistentCollection wrapper for that collection (remember, a PersistentCollection wraps a collection implementation type, implementing the same interface, so that it can do all the persistence work before/after delegating to the underlying collection implementation type).
So a custom collection implementation would consist of 3 parts:
Interface type
Implementation type (implements interface type)
Persistent wrapper type (implements interface type)
This will not only make it possible to write custom collections that work seemlessly with the Doctrine 2 ORM but also to write only a custom persistent wrapper type, for example to optimise the lazy-loading/initialization behavior of a particular collection to specific application needs.
It is not yet possible to do this but it will be. This is the only really elegant and fully functional way to write and use completely custom collections that integrate flawlessly in the transparent persistence scheme provided by Doctrine 2.
No, whenever Doctrine gives you back an implementation of the Doctrine\Common\Collections\Collection interface, it will be a Doctrine\ORM\PersistentCollection instance. You cannot put more custom logic on the collection. However that is not even necessary.
Say you have an entity (Order has many OrderItems), then a method to calculate the total sum of the order should not be located on the collection, but on the Order item. Since that is the location where the sum has meaning in your domain model:
class Order
{
private $items;
public function getTotalSum()
{
$total = 0;
foreach ($this->items AS $item) {
$total += $item->getSum();
}
return $total;
}
}
Collections however are only technical parts of the ORM, they help to implement and manage references between objects, nothing more.
Same question here, with a reference to the official doctrine Jira issue page with the details and status of this 'feature'... You can keep track of the development there!