Doctrine - encryption with dql listeners - php

I am attempting to encrypt certain database fields by adding a call to mysql AES_ENCRYPT (and AES_DECRYPT) using Doctrine DQL Hooks.
for SQL SELECT's I have a preDqlSelect() in my Doctrine_Record_Listener class, which goes through each parameter in the select fields, and adds a AES_DECRYPT() for encrypted fields.
But, it looks like calling save() on a doctrine model class only calls the preSave() listener and does not call any of the preDql* listeners.
Can anyone suggest a way of getting this to work or a better way of doing this?
Thanks

In order for these dql callbacks to be checked, you must explicitly turn them on. Because this adds a small amount of overhead for each query, it is off by default
$manager->setAttribute(Doctrine_Core::ATTR_USE_DQL_CALLBACKS, true);
Doctrine 1.2 Event listeners

Related

In Symfony, how to get QueryBuilder from default findBy method?

In Symfony 5, using Doctrine, how can I get QueryBuilder object (instead of results) from default entity repository methods like findBy, findOneBy, findAll?
I need QueryBuilder for:
Passing it to KnpPaginator (requires specifically QueryBuilder instead of results)
Possibly extending it with additional query logic in the future
I could just write a simple query (like $em->createQuery("SELECT a FROM Article a")), but I want to have access to filtering and ordering provided by default findBy method. I think writing my own QueryBuilder with filtering/sorting by any property would be a lot of work and I'm not sure I could implement it well even if I tried.
EDIT: even though it does not answer my question exactly, I have found a solution for my 1st use case (using KnpPaginator without writing custom queries): Custom data repository pagination.
This method allows to attach pagination to any query without changing it instead of writing a new one through QueryBuilder.

Force doctrine to always refresh

I've got a script that fetches data from a database using doctrine. Sometimes it needs to fetch the data for the same entity, the second time however it uses the identity map and therefor might go out of sync with the database (another process can modify the entities in the db). One solution that we tried was to set the query hint Query::HINT_REFRESH before we run the DQL query. We however would like to use it also with simple findBy(..) calls but that doesn't seem to work? We would also like to be able to set it globally per process so that all the doctrine SELECT queries that are run in that context would actually fetch the entities from the DB. We tried to set the $em->getConfiguration()->setDefaultQueryHint(Query::HINT_REFRESH, true); but again that doesn't seem to work?
Doctrine explicitly warns you that it is not meant to be used without a cache.
However if want to ignore this, then Cerad's comment (also mentioned in in this answer) sound right. If you want to do it on every query though you might look into hooking into a doctrine event, unfortunately there is no event for preLoad, only postLoad, but if you really don't care about performance you could create a postLoad listener which first gets the class and id of the loaded entity, calls clear on the entity manager and finally reloads it. Sounds very wrong to me though, I wash my hands of it :-)

Doctrine2 - is there a pre-selection hook?

I'm developing a ws with Symfony2 / Doctrine2, and I'm trying to hook into Doctrine2 lifecycle and trigger a function before any SELECT action - but without any luck. Basically, i'd like to dynamically manipulate the selection queries adding limit/offset when certain parameters are found in the request, but it seems that Doctrine2 hooks concern only insert, delete and update actions. Am i missing something?
Thanks.
U have to use Doctrine Filter
Doctrine 2.2 features a filter system that allows the developer to add SQL to the conditional clauses of queries, regardless the place where the SQL is generated (e.g. from a DQL query, or by loading associated entities).
A way to deal with this would be to register a custom event that is dispatched before a select. You have already referenced the source that shows examples of how to do it.

Doctrine entity remove vs delete query, performance comparison

While using doctrine, I noticed that, to delete an entity, I need to retrieve that entity by given parameter(name,id etc) and then call the remove method. On the other hand, in query, I can just execute delete query.
So, seems like, using ORM style requires two operation and general sql operation require one operation. That's why, I am a little confusing, whether we should use delete(or update) operation in ORM? Isn't it worse in performance? Or Is there anything else I am missing? Can it be done in any other way in ORM style?
In Doctrine2 you can call the delete on a proxy object, which is not loaded from the database. Just create a "dummy" object, something like:
$user = $em->getPartialReference('model\User', array('id' => $id));
$em->remove($user);
It doesn't require the initial query, but I'm not quite sure if Doctrine still does it internally on flush. I don't see it in the SqlLog.
Just to add, I think this is expected behavior of any decent ORM. It deals with objects and relations. It has to know that something exists before deleting it. ORM is not just a query generator. Generally, a native query will always be faster in any ORM. Any ORM adds a layer of abstraction and it takes some time to execute it. It is a typical tradeoff, you get some fancy features and clean code, but loose some on performance.
EDIT:
I'm glad it worked out for you. Actually I stumbled on another problem, which made me realize that proxies and partial objects aren't actually the same thing. Partial objects instance the real model class, and fill it with values you want. After you initialize a partial object lazy-loading doesn't work on it anymore. So for instance, if you make a partial object with only the id, and want to delete only if another object field satisfies some condition, it will not work, because that other field will always be null.
On the other hand, proxies do work with lazy-loading, and don't share the problems that partial objects have. So I would strongly suggest not to use getPartialReference method, instead you can do something like:
$user = $em->getReference('model\User', $id);
$em->remove($user);
The getReference method returns the object if it is already loaded or a proxy if it is not. A proxy can lazy-load all the other values if/when you need them. As for your example, they will behave exactly the same, but proxies are surely a better way to go.
Done!
for me it worked like this add line 3:
$user = $em->getReference('model\User', $id);
$em->remove($user);
$em->flush();

Using virtual fields in Doctrine_Query

Is there a way to insert logic based on virtual fields into a Doctrine_Query?
I have defined a virtual field in my model, "getStatus()" which I would ultimately like to utilize in a Where clause in my Doctrine_Query.
...
->AndWhere('x.status = ?',$status);
"status", however, is not a column in the table it is instead computed by business logic in the model.
Filtering the Collection after executing the query works in some situations, but not when a Doctrine_Pager is thrown in the mix, as it computes it's offsets and such before you have access to the Collection.
Am I best off ditching Doctrine_Pager and rebuilding that functionality after modifying the Doctrine_Collection?
If you can do it in SQL you can do it in Doctrine. All doctrine is doing is working out what you are putting into the DQL parser, be it strings or values and turning that into SQL then hydrating objects from the result.
You can't use Doctrine_Pager to page on non query objects, however you could use sfPager and pass it the results of the Doctrine_Collection as an array? In the worst case you could pass it the results of the query minus any limits in the query and let it handle the paging, however this is really inefficient.
It might be quicker to write the pager "old skool" like you would in plain old PHP.
I don't really know what business logic you're applying to work out the status, but if it's not live (as in, computed per request), I'd compute it on save (using a Doctrine Record Listener or simply a preSave/preInsert hook in the model) and store it in the table, or set up a symfony task to refresh it periodically and run that as a cronjob. That would let you query it in Doctrine just fine and boost performance as a fringe benefit.
Alternatively, if status is dependent on the state of related objects, you can put an event trigger on them that updates the status of the parent object when they're modified. It's hard to recommend a best approach without more context. :)

Categories