I need some help dealing with a relational table that is an entity due to the existence of an additional property.
Here is a gist of the entities in question: https://gist.github.com/chasepeeler/efd7efd890c58eafb81f
Do I have something configured wrong that is forcing me to do the flush in controller.php line 15?
I've also tried just updating the rank attribute of the queueItem record in the Queue::queueItems collection, but when I do that, it doesn't even save the changes to the database.
$queueItems->clear() does the same thing as clearQueueItems, but one time.
And if you want to override current queue state, you should just implement and call setQueueItems(ArrayCollection $queueItemList) method.
UnitOfWork will compute your changes to insert and remove new/deleted items.
Every OneToMany annotated field should implement setItems, addItem and removeItem methods, where Item is related entity name.
Your sortQueue method shouldn't persist and commit changes into database.
It should only return a sorted Collection.
Maybe I didn't get that, it's hard to say what you want to achieve, controller's code says me nothing.
Related
Short and easy question:
How to determine that Doctrine PHP Entity Object is new?
New - I mean is not in database and its not "update" action.
Most important thing - I need way to check it without any query like:
$manager->findOne($something);
Actually sometimes I tried to check "is ID null" but Im not 100% sure this method is valid or not. And other tip or probably core of this question - I seen something like:
$manager->getUnitOfWork()->isInIdentityMap($object);
Looks nice but I can't find what actually do function isInIdentityMap.
Is it true if it was persisted or removed? When this function say true and false?
//EDIT
I need to detect entity object created first time - existing only in php but not in database. Of course entity loaded from database to apply updates is not new for me - for example:
When you createing Comment object you need to increment commentCounter but it should be incremented only when you flushing this comment for first time.
You don't want to increment it when you updating or deleting existing comment.
How to check that comment is new and counter should be incremented.
Please explain in answers why your method is good/better
You can use
$entityManager->contains($entity)
Edit:
Based on your edit, i suggest to use an entity listener:
http://doctrine-orm.readthedocs.io/en/latest/reference/events.html#entity-listeners
So you don't need to check if the entity is new or not in many parts in your application when an entity is persisted, you only setup the entity listener and it works wherever you create and persist the entities.
I checked some docs and tested some things and I hope that everything I write is correct:
Method isInIdentityMap
$manager->getUnitOfWork()->isInIdentityMap($object);
is probably perfect for my case because it checks that my object exist in Identity Map, this map store only flushed objects or actually object with ID. New Object before persistence and after persist action still have NULL ID so its not in this map. This way as long as object was not flushed into database this method should work. (Map contains only objects loaded from database)
Method to check NULL ID
if($obj->getId() == null){
//code
}
should work too, its very similar to first methid but still Im not 100% sure it always work as I want and in addition we have first method so... Its better to use function prepared for it.
Method contains
$entityManager->contains($entity)
Do job but for other case. This method checks objects in entity manager but any persisted object, scheduled for any action is already tracked by entityManager. This function can help only as long as object is not persisted.
Other methods
Unit of work have many other methods, I didnt check them all but it seems we can easly check many other things using functions like:
->scheduleForInsert();
->scheduleForUpdate();
// etc
And other case - using Doctrine events event:
prePersist
prePersist - The prePersist event occurs for a given entity before the respective EntityManager persist operation for that entity is executed. It should be noted that this event is only triggered on initial persist of an entity (i.e. it does not trigger on future updates).
I have a Doctrine\ORM entity, consisting of new and existing database entities, created from Doctrine ObjectManager:merge(). Before flushing, I want to prevent duplicates (the context is an api where users could send e.g. duplicate city names within the same request).
As mentioned in this github issue it is recommended to flush after every persist() operation to be able to query my database for existing records including the ones persisted in this request. How could I do that?
My code is:
...
$object = $mapper->map($objectRaw, new $modelClassName());
$object = $em->merge($object);
# I need to intervene here I suppose
$em->flush();
I tried:
the hint mentioned on the github issue that dql would trigger a flush automatically, but after merge() that would imho mean that all new entites would be flushed, which I do not want before having checked for duplicates
lots of Lifecycle Events combinations, but I think that is not the way, the relevant ones already happened in the merge
It seems that I need a way to flush each entity one by one and do my checks at that time, something like:
Store scheduled insertions from UnitOfWork.
Clear list of scheduled insertions.
Persist and flush every insertion one by one and do my checks.
Or another idea - thank you very much!
Edit: Another idea would probably be to simply do my checks and manipulations on the object before $em->merge($object);. But you would loose the possibility of matching against repositories. So still, the question keeps me busy...
I have created a crud system. Here I have a main model and then dependent details model. So their are multiple rows (some times > 100 ) entered into details model related to parent model. All operations handled through grid ( inline edit ). So create, update, delete operations are performed through single request (logical checking via DB).
Now I am considering to use DB transaction to whole operations. But I am confused, how I can implement this using same structure. I already have suggestions to move my all code to one model, So transaction can be applied there. But I am thinking, if any other approach can be used for retain separation of main and details model code.
Are you using AJAX for the changes or does it rely on manual form submissions?
You can use what's called a UnitOfWork pattern.
Save any changes that the user makes to each line of the grid but don't actually commit them to the DB. Then, place a geneic save button on the page that will cause your server to actually commit all the changes through a transaction.
You can keep a list server side of each row that the user changes. You don't need to track all the rows because if they don't change anything you don't need to save anything.
What sort of approach are you using in your Models? Do your models know about their own persistence (do you do things like $user->save()), or are you doing a more data-mapper approach ($userManager->save($userEntity))? The latter makes transaction handling a lot easier.
If you're doing the active-record type of patter ($user->save()), your best bet is probably just to manually grab your db connection and manage the transaction in your controller.
If you're doing data-mapper stuff, you have more options, up to and including doing a whole unit-of-work implementation.
As for my last comment, Moving code to parent model is my solution for now. So I think I should mark this thread answered.
Is there any proxying in place between Zend DB Table and Zend DB Row? For example, if I override the DB_Table delete() method to merely flag deleted records, will I need to do the same thing in DB_Table_Row? Or does row proxy to table?
If proxying is in place, in which direction does it occur? (Row proxies to table?) And for which methods? (Row delete() and save() -to- table delete(), update() and insert()?)
I realise I could test this myself but chance are you will be a lot faster (if you don't already know the answer...)
Thanks!
EDIT
The reason for the question is that I am developing some models which will include ACL. Since I have ACL in controllers too, I am planning only to override selected methods in the DB classes. For example, I want to ensure that a Member can delete their own record only. (I think I need to use ACL asserts to do this).
So I was asking the question above in order to determine whether I had to override pairs of methods (i.e. one in the Table class, one in the Row class), or whether I could just override one. Judging by the responses, however, I'm now wondering whether I'm asking the wrong question.
How do experienced developers deal with this kind of situation? Perhaps you choose to work with just one delete method (e.g. from the Row class). (Ditto for the update method too). If so, do you override the Table class delete to prevent inadvertant usage?
I am curious... Thanks...
From what I understand, the delete method in Zend_DB_Row employs delete method from Zend_DB_Table. Thus, if you overwrite delete from Zend_DB_Table it should be seen by delete in Zend_DB_Row.
Hope this helps. Anyway, if this would be not the case, please let me know.
Line 627 of Zend_Db_Table_Row_Abstract
/**
* Execute the DELETE (this may throw an exception)
*/
$result = $this->_getTable()->delete($where);
gets the table and executes the delete method.
Line 1182 of Zend_Db_Table_Abstract
return $this->_db->delete($tableSpec, $where);
This will call the Zend_Db_Adapter_Abstract::delete().
IMO, it may be best to over write the delete method in your adapter class. This is will ensure that no matter where the delete request comes from, your custom delete logic will be executed.
I am soft-deleting objects in a MySQL database and using the Propel ORM. I have gotten soft-deleting to work, but at the cost of losing my enforced parent-child relationships, since the actual rows are not being deleted.
Is there any way for Propel to know that a record has been soft-deleted when you access it, so that a null-reference exception is not thrown? This way, although a parent has been deleted, its child can still read it's relation, but when updating a child, or creating a new child, the deleted parent is not accessible.
For example,
Book has an AuthorId, and if the author belonging to AuthorId is soft-deleted, then:
$book->getAuthor();
would return the correct author (for viewing purposes only). However, if a new book was added, the author that was soft-deleted is not available to be selected.
Does anybody know if that functionality is built into Propel?
Soft delete is a broken abstraction. You should use the archivable behavior instead (see why in the Propel blog: http://propelorm.org/blog/2011/08/29/introducing-archivable-behavior-and-why-soft-delete-is-deprecated.html)
I'm not sure why an Author would be allowed to be deleted but his works would not (or, basically, why this comes up as a scenario in your project) but you can create custom criteria and execute it. The following code depends on the version of Propel you are using (but the concept remains the same):
$c = new Criteria();
$c->getNewCriterion(self::AUTHOR_ID, $parentId);
return self::doSelect($c, $connection);
Just stumbled across this question. Seems like it would make a lot more sense to not use soft delete for the functionality you are describing. I would highly advise that you create a field to flag whether authors are enabled, i.e. a boolean field called isEnabled.
You could then use the generated filter method for AuthorQuery class, in this case
AuthorQuery::create->filterByisEnabled()
->find();
If an object is still going to be used in the application it isn't really appropriate to delete. Soft delete functionality is only really for reference or revert mistakes.