I am programming my first symfony project and I stuck at a problem:
I have a entity I called it "load" which refers to other entities which a call "transaction" (x transactions belongs to 1 load) :
/**
* #ORM\OneToMany(targetEntity="Transaction", mappedBy="load")
*
*/
private $transactions;
The transactions can be flagged as deleted but they keep stored in the database.
I created a custom repository and some methods which deliver me the undeleted transactions.
But if I want to fetch a load with all it's transactions, I call
$load = $loadRepository->find($id);
it does what it is supposed. It fetches all transactions from the database which are referenced to the given load.
But I don't want to have the deleted transactions in my result. How can I achive this? I have absolutely no approach. Sure, I can iterate over the transactions and remove the deleted ones but I think there is a better solution.
I tried to register a repository for the transactions (this works) and override the find-method (this doesn't work).
Is there another method which is internally called and I have to override?
thank you in advance!
If I have correctly understand your question, this behavior already exist with the doctrine extension SoftDeletable, you can find documentation here
You just have to add something like deleteAt property on your Transaction entity then all entities with data inside this field will be automatically filtered like if they are really deleted. If you want to find all of the Transaction entities you can always disable the filter on a query.
I found a solution:
#config.yml:
doctrine:
orm:
filters:
deletedFilter:
class: AppBundle\Filter\SoftDeletedFilter
enabled: true
_
namespace AppBundle\Filter;
use Doctrine\ORM\Mapping\ClassMetaData,
Doctrine\ORM\Query\Filter\SQLFilter;
class SoftDeletedFilter extends SQLFilter
{
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{
if(!is_subclass_of($targetEntity->rootEntityName, "AppBundle\Entity\SoftDeleteableInterface")){
return "";
}
return $targetTableAlias.'.deleted = 0';
}
}
Now, all entities which implements the (empty) interface "SoftDeleteableInterface" will not be included if the deleted-value is not 0.
Thank you anyway for the answers/comments
Related
What I am trying to achieve
Users would be able to configure Doctrine entities through an HTML form on a website.
Users would be able to define new entities, as well as add and delete fields for existing entities. (Similar to Drupal's content types)
The Doctrine entities would get dynamic properties based on the configuration that the user supplied through the web UI.
Either the single DB table per Doctrine entity would be altered dynamically whenever an entity configuration changes; Or there could be multiple tables used per single entity (each new entity field would get its own table).
Done so far
I have been researching this for the past few days without much success but I stumbled across this answer which seems quite related to what I am trying to achieve.
I have registered and added the loadClassMetadata listener which maps the field foo:
// src/DynamicMappingTest/AdminBundle/EventListener/MappingListener.php
namespace DynamicMappingTest\AdminBundle\EventListener;
use Doctrine\ORM\Event\LoadClassMetadataEventArgs;
class MappingListener
{
public function loadClassMetadata(LoadClassMetadataEventArgs $eventArgs)
{
$classMetadata = $eventArgs->getClassMetadata();
if ($classMetadata->getName() != 'DynamicMappingTest\\AdminBundle\\Entity\\CustomNode')
{
// Not the CustomNode test class. Do not alter the class metadata.
return;
}
$table = $classMetadata->table;
$oldName = $table['name']; // ... or $classMetaData->getTableName()
// your logic here ...
$table['name'] = 'custom_node';
$classMetadata->setPrimaryTable($table);
$reflClass = $classMetadata->getReflectionClass();
dump($reflClass);
// ... or add a field-mapping like this
$fieldMapping = array(
'fieldName' => 'foo',
'type' => 'string',
'length' => 255
);
$classMetadata->mapField($fieldMapping);
}
}
Now, this all works as long as I have the foo property declared in the DynamicMappingTest\AdminBundle\Entity\CustomNode class:
// src/DynamicMappingTest/AdminBundle/Entity/CustomNode.php
namespace DynamicMappingTest\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* CustomNode
*
* #ORM\Table()
* #ORM\Entity(repositoryClass="DynamicMappingTest\AdminBundle\Entity\CustomNodeRepository")
*/
class CustomNode
{
...
private $foo;
}
Problem
However, there is no way for me to know what properties the users will define for their custom entities. If I remove the foo property from the CustomNode class, the ReflectionClass that I get from the ClassMetadata will naturally not include the foo property and so I get the following exception whenever the mapField() in MappingListener is executed:
ReflectionException: Property DynamicMappingTest\AdminBundle\Entity\CustomNode::$foo does not exist
in vendor/doctrine/common/lib/Doctrine/Common/Persistence/Mapping/RuntimeReflectionService.php at line 80
77. */
78. public function getAccessibleProperty($class, $property)
79. {
80. $reflectionProperty = new ReflectionProperty($class, $property);
81.
82. if ($reflectionProperty->isPublic()) {
83. $reflectionProperty = new RuntimePublicReflectionProperty($class, $property);
Questions
Is it possible to have fully configurable dynamic Doctrine entities?
Am I on the right track with my approach? If not, could you suggest an alternative?
How could I have truly dynamic class properties? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration?
Is it possible to have fully configurable dynamic Doctrine entities?
Doctrine generates proxy classes for you entities. That means that doctrine generates PHP code with class, which extends your Entity class and overrides the methods - puts some custom logic and then calls the parent method.
So, I think that the only way to make this really happen is to generate the PHP code for entities in your code. That is, every time entity is created in your website, you should generate PHP file with that entity, then run migrations.
Am I on the right track with my approach? If not, could you suggest an alternative?
I don't think that you should use Doctrine ORM at all in this case, at least in the way you're trying to do that.
Generally, ORM is used for easier/more manageable programming. That is, you can set relations, use lazy-loading, unit of work (change entity properties and then just flush) etc. If your entities are generated dynamically, what features will you use at all? Developer will not write code for these entities, because, as you've said, there is no way to know what fields it will have.
You haven't provided concrete use-case - why do you want to do that in the first place. But I imagine that it could be really done in some easier way.
If users can store any structure at all, should you use MySQL at all? ElasticSearch or similar solutions could be really much better in such cases.
How could I have truly dynamic class properties? Or should I be generating new Doctrine entity PHP classes whenever the users change the entity configuration?
As I've mentioned - yes. Unless you would want to override or replace some of Doctrine code, but I imagine it could be lots of it (proxy classes etc.)
In Laravel 4 there are Model events for creating, created, updating, updated etc.
Has anyone found a way to do something similar to a reading, read event without hacking / extending the QueryBuilder class?
Even if it isn't an event per say, I would like to find a way to achieve this before/during/after (either one of those) query results have been injected into the model attributes.
So far I am just overriding the getAttributeFromArray method on my core/base model class which works but obviously runs the logic everytime you try to grab an attribute/property in the model (Could end up being a costly operation down the line).
Thanks!
I was able to achieve this by adding and overriding 1 method in my core/base model class (extends eloquent\model)
public static function read($callback)
{
static::registerModelEvent('read', $callback);
}
public function setRawAttributes(array $attributes, $sync = false)
{
parent::setRawAttributes($attributes,$sync);
$this->fireModelEvent('read');
}
This way my read event will only fire once when the results are injected into the model(s). instead of having the event run per __get call on the model.
I've been researching and reading a lot about working with separate layers in PHP to create maintainable and readable code.
However, I see a lot of code where the entity and the database access is placed in one class.
For example:
class User{
public $id;
public $username;
public $database;
function add(){
$database->query ....
}
}
I find this rather strange because here you are mixing the User class with database elements which makes it more difficult to maintain.
I like working like this:
a separate database class
a user class
a userData class
This works like this:
$database = new Database();
$database->openConnection();
$dataUser = new DataUser($db);
$user = new User(1,"myname");
$dataUser->saveUser($user);
So I'm wondering, am I working the right way or is the first way a better way to create code?
I find may way very easy to maintain because you have a separate entity and a separate database class to handle the database actions.
What i do :
My models are not Entities linked to the database(when i'm not using doctrine) , so no "active record" methods. An object doesnt know how to fetch its dependencies ( for instance , a user may have n comments, my model doesnt know how to get comments ).
class User{
private $name;
private $password;
// getter and setters
}
i have services that hold some business logic that can fetch models from providers, a service can have many providers.
class UserService{
function __construct(IUserProvider $userProvider){
$this->userProvider = $userProvider
}
function getUsers(){
// return an array of user objects
return $this->userProvider->getUsers();
}
}
finally i have a data provider that knows how to request datas from the database , a text file , a json file , a webservice :
class UserProvider implements IUserProvider{
function __construct(Connection $connection){
$this->connection = $connection;
}
function getUsers(){
return $this->toUsers($this->connection->fetchAssoc("Select * from users"));
}
function toUsers(array $datas){
// convert user records to an array of User
(...)
return $users;
}
}
then the interface
interface IUserProvider{
/**#return array an array of User */
function getUsers();
}
if i need to get a user comments , then my comment service knows how fetch comments from a user id. So to get a user and its comments , i need 2 requests to the database. one from the UserProvider , the other from the CommentProvider.
so i have 3 layers :
my application layer ( display users , respond to requests whatever ... )
my service layer ( which has to work with a command line interface and is not aware of my web application , except for password encoding which is usually binded to the framework i use , and ACL stuffs maybe ...)
my data access layer which knows nothing about the other layers ,
the only way my layers communicate is through Models i pass from layer to layer.
And all my classes are built with a dependency injection container, so the wiring is not a problem.
Here is an exemple of an app i made,it's open source : https://github.com/Mparaiso/silex-bookmarkly
Any thoughts welcome.
easy to maintain because you have a separate entity and a separate
database class
It appears you're saying that you wish to move away from an Active Record approach to a Data Mapper/Entity/Repository approach. That's a good direction to move in because it employs better separation of concerns. You can build this yourself but you might want to take a look at solutions like Doctrine where it allows you to do something along the lines of:
$product = new Product();
$product->setName($newProductName);
$entityManager->persist($product);
The $product entity is just a POPO (Plain Old PHP Object) that contains the record data and is unaware of how it's persisted and, when persistence is needed, is passed into the entity manager to take care of the storing.
Personally, I think abstracting UserData from User is likely to be overkill. As, in this case, UserData is likely to be very similar to ProductData for example - they're still going to contain an add($data), find($id) etc.
In your case, User is a model in the MVC approach, and is totally acceptable to contain Database store/retrieve logic. You will however likely find that you are, again recreating the same DB methods in the User class that you have in other Models. This is where you may start to look at an ORM implementation. Whereby the common DB access methods are defined in an abstract class that all your models then extend and override as necessary.
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!
I'm creating an ORM in PHP, and I've got a class 'ORM' which basically creates an object corresponding to a database table (I'm aiming for similar to/same functionality as an ActiveRecord pattern.) ORM itself extends 'Database', which sets up the database connection.
So, I can call: $c = new Customer();
$c->name = 'John Smith';
$c->save();
The ORM class provides this functionality (sets up the class properties, provides save(), find(), findAll() etc. methods), and Customer extends ORM. However, in the future I may be wanting to add extra public methods to Customer (or any other model I create), so should this be extending ORM or not?
I know I haven't provided much information here, but hopefully this is understandable on a vague explanation, as opposed to posting up 300+ lines of code.
I agree with the other answers here - put the additional methods into a descendant class. I'd also add an asterisk to that though: each time you extend the class with extra methods, think about what you are trying to achieve with the extension, and think about whether or not it can be generalised and worked back into the parent class. For example:
// Customer.class.php
function getByName($name) {
// SELECT * FROM `customer` WHERE `name` = $name
}
// ** this could instead be written as: **
// ORM.class.php
function getByField($field, $value) {
// SELECT * FROM `$this->table` WHERE `$field` = $value
}
You're certainly thinking correctly to put your business logic in a new class outside your 'ORM'. For me, instead simply extending the ORM-class, I'd rather encapsulate it with a new, value object class to provide an additional degree of freedom from your database design to free you up to think of the class as a pure business object.
Nope. You should use composition instead of inheritance. See the following example:
class Customer {
public $name;
public function save() {
$orm = new ORM('customers', 'id'); // table name and primary key
$orm->name = $this->name;
$orm->save();
}
}
And ORM class should not extend Database. Composition again is best suited in this use case.
Yes, place your business logic in a descendant class. This is a very common pattern seen in most Data Access Layers generation frameworks.
You should absolutely extend the ORM class. Different things should be objects of different classes. Customers are very different from Products, and to support both in a single ORM class would be unneeded bloat and completely defeat the purpose of OOP.
Another nice thing to do is to add hooks for before save, after save, etc. These give you more flexibility as your ORM extending classes become more diverse.
Given my limited knowledge of PHP I'm not sure if this is related, but if you're trying to create many business objects this might be an incredibly time consuming process. Perhaps you should consider frameworks such as CakePHP and others like it. This is nice if you're still in the process of creating your business logic.
You're definitely thinking along the right lines with inheritance here.
If you're building an ORM just for the sake of building one (or because you don't like the way others handle things) than go for it, otherwise you might look at a prebuilt ORM that can generate most of your code straight from your database schema. It'll save you boatloads of time. CoughPHP is currently my favorite.
I have solved it like this in my Pork.dbObject. Make sure to check it out and snag some of the braincrunching I already did :P
class Poll extends dbObject // dbObject is my ORM. Poll can extend it so it gets all properties.
{
function __construct($ID=false)
{
$this->__setupDatabase('polls', // db table
array('ID_Poll' => 'ID', // db field => object property
'strPollQuestion' => 'strpollquestion',
'datPublished' => 'datpublished',
'datCloseDate' => 'datclosedate',
'enmClosed' => 'enmclosed',
'enmGoedgekeurd' => 'enmgoedgekeurd'),
'ID_Poll', // primary db key
$ID); // primary key value
$this->addRelation('Pollitem'); //Connect PollItem to Poll 1;1
$this->addRelation('Pollvote', 'PollUser'); // connect pollVote via PollUser (many:many)
}
function Display()
{
// do your displayĆng for poll here:
$pollItems = $this->Find("PollItem"); // find all poll items
$alreadyvoted = $this->Find("PollVote", array("IP"=>$_SERVER['REMOTE_ADDR'])); // find all votes for current ip
}
Note that this way, any database or ORM functionality is abstracted away from the Poll object. It doesn't need to know. Just the setupdatabase to hook up the fields / mappings. and the addRelation to hook up the relations to other dbObjects.
Also, even the dbObject class doesn't know much about SQL. Select / join queries are built by a special QueryBuilder object.