Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Using a Doctrine EventListener to keep a record from being returned?
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
Jake Smith  
View profile  
 More options Nov 25 2009, 12:01 pm
From: Jake Smith <jake.smit...@gmail.com>
Date: Wed, 25 Nov 2009 11:01:58 -0600
Local: Wed, Nov 25 2009 12:01 pm
Subject: Re: [DallasPHP:180] Using a Doctrine EventListener to keep a record from being returned?

Adam,

Not quite sure why, but your blog crashes my Safari on iPhone.....just FYI.

Jake Smith
[t] @jakefolio
[w] www.jakefolio.com

On Wed, Nov 25, 2009 at 9:52 AM, Adam Jensen <jazzsli...@gmail.com> wrote:
> Thanks again for your help with this; I went through a couple of bug
> reports to find the answer, but I think I've got it working pretty smoothly
> now.

> For anyone who's interested, I've blogged the complete solution at
> http://jazzslider.org/2009/11/25/using-zend-acl-with-doctrine-record-...

> (As a sidenote: this blog is brand-new, and I'm not totally satisfied with
> its cross-browser support …so I apologize if it doesn't look quite right
> yet…but the content should all be there :)

> Thanks again!
> Adam

> On Tue, Nov 17, 2009 at 12:00 PM, Jake Smith <jake.smit...@gmail.com>wrote:

>> Adam,

>> I would submit it as a bug.  It is either a bug or there is an
>> undocumented way to handle such situation.
>> http://trac.doctrine-project.org/wiki/ReportBug

>> Jake Smith
>> [t] @jakefolio
>> [w] www.jakefolio.com

>> On Tue, Nov 17, 2009 at 6:28 AM, Adam Jensen <jazzsli...@gmail.com>wrote:

>>> Hello!

>>> OK, I did some experimentation on this yesterday evening, and I think I
>>> have a clearer sense of at least part of the problem.

>>> First thing I needed to find out is which listeners were actually firing
>>> when, so I wrote two very simple listeners (an event listener and a record
>>> listener), each implementations of Doctrine_Overloadable (see last part of Creating
>>> a New Listener<http://www.doctrine-project.org/documentation/manual/1_1/en/event-lis...>);
>>> they looked like this:

>>> [code]
>>> class My_Record_Listener_Tester extends Doctrine_Overloadable
>>> {
>>>   public function __call($methodName, $args)
>>>   {
>>>     echo "Doctrine_Record_Listener::$methodName" . PHP_EOL;
>>>   }
>>> }

>>> // and then the same thing for Doctrine_EventListener
>>> [/code]

>>> I then wrote a simple CLI script to bootstrap my Doctrine manager and
>>> connection, attached these listeners as appropriate
>>> (Doctrine_Manager::addListener and Doctrine_Manager::addRecordListener), and
>>> ran the following test code:

>>> [code]
>>> echo "Running Doctrine_Connection::getTable('Post')..." . PHP_EOL;
>>> $table = $conn->getTable('Post');
>>> echo "...done." . PHP_EOL;

>>> echo "Running Doctrine_Table::findAll()..." . PHP_EOL;
>>> $records = $table->findAll();
>>> echo "...done." . PHP_EOL;
>>> [/code]

>>> The first time I tried this, this is all that came out:

>>> [output]
>>> Running Doctrine_Connection::getTable('Post')...
>>> ...done.
>>> Running Doctrine_Table::findAll()...
>>> EventListener::preConnect
>>> EventListener::postConnect
>>> EventListener::preQuery
>>> EventListener::postQuery
>>> ...done.
>>> [/output]

>>> Not a whole lot there to hook into; *Connect() won't help me, and the
>>> *Query() methods aren't really even documented.  But I was wondering at this
>>> point, why in the world were none of the hydration hooks running?  After
>>> all, I was getting back fully hydrated Post objects.

>>> I took a closer look at my Post model at that point and realized that
>>> it's utilizing several built-in Doctrine templates ("actAs" stuff:
>>> timestampable, sluggable, etc.); since templates make heavy use of event and
>>> record listeners to do their work, I thought I'd test it without them
>>> attached, just to see if there were a conflict.  Sure enough, when I ran the
>>> script again:

>>> [output]
>>> Running Doctrine_Connection::getTable('Post')...
>>> ...done.
>>> Running Doctrine_Table::findAll()...
>>> Record_Listener::getOption
>>> Record_Listener::preDqlSelect
>>> EventListener::preConnect
>>> EventListener::postConnect
>>> EventListener::preQuery
>>> EventListener::postQuery
>>> Record_Listener::getOption
>>> Record_Listener::preHydrate
>>> Record_Listener::getOption
>>> Record_Listener::postHydrate
>>> Record_Listener::getOption
>>> Record_Listener::preHydrate
>>> Record_Listener::getOption
>>> Record_Listener::postHydrate
>>> ...done.
>>> [/output]

>>> Suddenly there are a whole slew of Record_Listener events firing that
>>> weren't firing when the actAs templates were still attached.  That hydration
>>> sequence (getOption, preHydrate, getOption, postHydrate) fires once for
>>> every record returned…and there's also a getOption, preDqlSelect sequence
>>> that fires before the *Query() events.

>>> Unfortunately, those actAs templates are pretty important, and so far I
>>> haven't found a way to get all those extra hooks to fire if _even one_
>>> template is still attached to the model.

>>> Do you know if this is a documented behavior?  If so, is there a
>>> workaround?

>>> I'm going to cross-post this in the Doctrine list too, since I think it
>>> may be useful information …either that, or I'm missing something obvious :)

>>> Thanks!
>>> Adam

>>> On Mon, Nov 16, 2009 at 3:12 PM, Adam Jensen <jazzsli...@gmail.com>wrote:

>>>> Jake,

>>>> Haven't tried that one yet, no…was a bit confused about the difference
>>>> between postExec, postExecute, and postStmtExecute as described in the docs
>>>> at
>>>> http://www.doctrine-project.org/documentation/manual/1_1/en/event-lis...with such similar names, it's tough to know which one to try :)

>>>> I traced through some of the source, though, and it looks like the
>>>> Doctrine_Connection::exec() method handles queries that change things
>>>> (inserts, updates, deletes), while Doctrine_Connection::execute() handles
>>>> queries that return things (selects).  So I'm guessing the hooks should work
>>>> similarly, except that if you include prepared statement parameters, the
>>>> *StmtExecute() hooks are required instead (if I'm reading the footnote in
>>>> the manual correctly).  Does that all sound right?

>>>> If I get a chance tonight, I'll try a few more of these methods
>>>> out…maybe in a testing environment where I can isolate exactly what's
>>>> happening when…figuring out how all this works in the context of a full
>>>> application is turning out to be a bit messy.

>>>> Meanwhile, I appreciate the help; pretty excited to get this working!

>>>> Thanks,
>>>> Adam

>>>> On Mon, Nov 16, 2009 at 1:57 PM, Jake Smith <jake.smit...@gmail.com>wrote:

>>>>> Adam,

>>>>> Have you tried postExec()?

>>>>> Jake Smith
>>>>> [t] @jakefolio
>>>>> [w] www.jakefolio.com

>>>>> On Mon, Nov 16, 2009 at 1:26 PM, Adam Jensen <jazzsli...@gmail.com>wrote:

>>>>>> Jake,

>>>>>> Right, that's what I'd like to have happen.  Ideally at the controller
>>>>>> layer I could just issue a typical $table->findAll() call, and then the
>>>>>> event listener would filter out the impermissible records so that only the
>>>>>> permissible ones were returned.

>>>>>> Doesn't look like there is a postDqlSelect() hook available in
>>>>>> Doctrine_Record_Listener; that sounds like it'd be perfect, but I don't
>>>>>> think it's available.

>>>>>> I did try using Doctrine_Record_Listener::postHydrate(), since within
>>>>>> that context the $event->data property contains the fully-hydrated object
>>>>>> (which is what my ACL implementation needs to see).  Problem is, I don't
>>>>>> think postHydrate is really designed such that you can prevent the object
>>>>>> from being returned altogether; also, it doesn't seem to run exactly when
>>>>>> I'm expecting it to …I may be able to post an example of what I mean later,
>>>>>> can't really work on it at the moment.

>>>>>> I'm also going to look into postFetchAll() later when I get the
>>>>>> chance; looks promising, but I don't know if it'll have the hydrated object
>>>>>> available yet.  Maybe I'm going about all this the wrong way :)

>>>>>> Thanks!
>>>>>> Adam

>>>>>> On Mon, Nov 16, 2009 at 1:00 PM, Jake Smith <jake.smit...@gmail.com>wrote:

>>>>>>> Adam,

>>>>>>> From a logic standpoint wouldn't you want to NOT return
>>>>>>> records/results if the user does not have permission to see?  Also, couldn't
>>>>>>> you do postDqlSelect if you want to handle this post select?

>>>>>>> Jake Smith
>>>>>>> [t] @jakefolio
>>>>>>> [w] www.jakefolio.com

>>>>>>> On Mon, Nov 16, 2009 at 12:43 PM, Adam Jensen <jazzsli...@gmail.com>wrote:

>>>>>>>> Jake,

>>>>>>>> Looked into that a bit, and put it into practice on, e.g., supplying
>>>>>>>> a default orderBy clause for all select queries against a particular
>>>>>>>> component…pretty cool stuff, really, since doing things like that at the
>>>>>>>> listener level will likely allow me to get rid of an entire abstraction
>>>>>>>> layer once I've got it all figured out.

>>>>>>>> However, what I'm looking to do in this instance is a bit different.
>>>>>>>>  My access control logic is all in PHP (via Zend_Acl) rather than in the
>>>>>>>> database, so what I need to be able to do is filter out impermissible
>>>>>>>> results _after_ the query has already returned its result set.  It's not
>>>>>>>> something I can really include in the query, unfortunately.

>>>>>>>> Any ideas on how to deal with that?

>>>>>>>> Thanks!
>>>>>>>> Adam

>>>>>>>> On Mon, Nov 16, 2009 at 10:38 AM, Jake Smith <
>>>>>>>> jake.smit...@gmail.com> wrote:

>>>>>>>>> Adam,

>>>>>>>>> Have you tried the preDqlSelect?

>>>>>>>>> You will need to extend the Doctrine_EventListener.

>>>>>>>>> http://www.doctrine-project.org/documentation/manual/1_1/en/event-lis...

>>>>>>>>> Jake Smith
>>>>>>>>> [t] @jakefolio
>>>>>>>>> [w] www.jakefolio.com

>>>>>>>>> On Fri, Nov 13, 2009 at 1:38 PM, jazzslider <jazzsli...@gmail.com>wrote:

>>>>>>>>>> Hello!

>>>>>>>>>> Gonna post this to the official Doctrine mailing list as soon as
>>>>>>>>>> my
>>>>>>>>>> membership there is approved, but I figured since we talked about
>>>>>>>>>> Doctrine this past week it's fair game to ask here too :)

>>>>>>>>>> In one of my projects, I'm trying to do application-level access
>>>>>>>>>> control on my Doctrine models.  My access control system isn't
>>>>>>>>>> database-driven so I can't really include access control logic at
>>>>>>>>>> the
>>>>>>>>>> query level …as a result, I'm having to perform the checks after
>>>>>>>>>> the
>>>>>>>>>> query has returned all its data, like so:

>>>>>>>>>> [code]
>>>>>>>>>> // for single records...
>>>>>>>>>> $record = $doctrineTable->find($id);
>>>>>>>>>> if (!$acl->isAllowed($role, $record, 'read')) {
>>>>>>>>>>    // Set $record to false so it will appear to later code
>>>>>>>>>>    // as though the requested record was not found.
>>>>>>>>>>    $record = false;
>>>>>>>>>> }

>>>>>>>>>> // for multiple records...
>>>>>>>>>> $records = $doctrineTable->findAll();
>>>>>>>>>> foreach ($records as $key => $record) {
>>>>>>>>>>    if (!$acl->isAllowed($role, $record, 'read')) {
>>>>>>>>>>        // Remove the record from the collection so it will
>>>>>>>>>>        // not show up to later code.
>>>>>>>>>>        $records->remove($key);
>>>>>>>>>>    }
>>>>>>>>>> }
>>>>>>>>>> [/code]

>>>>>>>>>> Now, this works, but it gets pretty danged repetitive, and has a
>>>>>>>>>> tendency to muddy up my controller scripts significantly.  I'd
>>>>>>>>>> much
>>>>>>>>>> rather allow the model layer to handle this directly, and after
>>>>>>>>>> Jake's
>>>>>>>>>> presentation on Tuesday I realized that Doctrine's event and
>>>>>>>>>> record
>>>>>>>>>> listeners might be able to help.

>>>>>>>>>> I've managed to get things working for other kinds of operations
>>>>>>>>>> (create, update, and delete) by using the preInsert(),
>>>>>>>>>> preUpdate(),
>>>>>>>>>> and preDelete() methods of Doctrine_Record_Listener like so:

>>>>>>>>>> [code]
>>>>>>>>>> class My_Doctrine_Record_Listener_Acl extends
>>>>>>>>>> Doctrine_Record_Listener
>>>>>>>>>> {
>>>>>>>>>>   public function __construct($acl, $currentRole);

>>>>>>>>>>   public function preInsert(Doctrine_Event $event)
>>>>>>>>>>   {
>>>>>>>>>>      $resource = $event->getInvoker();
>>>>>>>>>>      if (!$this->getAcl()->isAllowed($this->getCurrentRole(),
>>>>>>>>>> $resource, 'create')) {
>>>>>>>>>>         throw new My_Model_Exception('You are not allowed to do
>>>>>>>>>> that.');
>>>>>>>>>>      }
>>>>>>>>>>   }

>>>>>>>>>>   // and then preUpdate and preDelete too
>>>>>>>>>> }
>>>>>>>>>> [/code]

>>>>>>>>>> However, for the "read" operations in my first code sample, I'm
>>>>>>>>>> having
>>>>>>>>>> trouble figuring out a couple of things.  First off, I'm not sure
>>>>>>>>>> what
>>>>>>>>>> listener method to implement…it's a bit difficult to tell which
>>>>>>>>>> listener is firing when, and the documentation is a bit terse.
>>>>>>>>>> Second, I'm not really sure what to do once I've got the listener
>>>>>>>>>> figured out …the desired behavior is that if a record isn't
>>>>>>>>>> allowed
>>>>>>>>>> for the role defined in the listener object, the table will simply
>>>>>>>>>> return whatever it would've returned if that record didn't even
>>>>>>>>>> exist
>>>>>>>>>> in the first place.

>>>>>>>>>> I've tried this out in the Doctrine_Record_Listener::postHydrate()
>>>>>>>>>> hook, since I figured that would definitely get called for every
>>>>>>>>>> record returned by any given SELECT query …but it doesn't always
>>>>>>>>>> seem
>>>>>>>>>> to fire when I expect it to (e.g., if I call $table->findAll(), it
>>>>>>>>>> doesn't seem to be firing for the records being returned), and
>>>>>>>>>> when it
>>>>>>>>>> does fire, I don't know how to tell it not to return the
>>>>>>>>>> record…maybe
>>>>>>>>>> set $event->data to NULL, or call $event->skipOperation()?

>>>>>>>>>> Anyway, I thought I'd go ahead and ask if anyone had run into this
>>>>>>>>>> kind of use case before, or if there's a better approach I'm not
>>>>>>>>>> considering.  Any ideas?

>>>>>>>>>> Thanks!
>>>>>>>>>> Adam

>>>>>>>>>> --

>>>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>>>> Groups "DallasPHP" group.
>>>>>>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>>>>>>> To unsubscribe from this group, send email to
>>>>>>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>>>>>>> .
>>>>>>>>>> For more options, visit this group at
>>>>>>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>>>>>>>  --
>>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>>> Groups "DallasPHP" group.
>>>>>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>>>>>> To unsubscribe from this group, send email to
>>>>>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>>>>>> .
>>>>>>>>> For more options, visit this group at
>>>>>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>>>>>>  --
>>>>>>>> You received this message because you are subscribed to the Google
>>>>>>>> Groups "DallasPHP" group.
>>>>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>>>>> To unsubscribe from this group, send email to
>>>>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>>>>> .
>>>>>>>> For more options, visit this group at
>>>>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>>>>>  --
>>>>>>> You received this message because you are subscribed to the Google
>>>>>>> Groups "DallasPHP" group.
>>>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>>>> To unsubscribe from this group, send email to
>>>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>>>> .
>>>>>>> For more options, visit this group at
>>>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>>>>  --
>>>>>> You received this message because you are subscribed to the Google
>>>>>> Groups "DallasPHP" group.
>>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>>> To unsubscribe from this group, send email to
>>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>>> .
>>>>>> For more options, visit this group at
>>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>>>  --
>>>>> You received this message because you are subscribed to the Google
>>>>> Groups "DallasPHP" group.
>>>>> To post to this group, send email to dallasphp@googlegroups.com.
>>>>> To unsubscribe from this group, send email to
>>>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>>>> .
>>>>> For more options, visit this group at
>>>>> http://groups.google.com/group/dallasphp?hl=.

>>>  --
>>> You received this message because you are subscribed to the Google Groups
>>> "DallasPHP" group.
>>> To post to this group, send email to dallasphp@googlegroups.com.
>>> To unsubscribe from this group, send email to
>>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>>> .
>>> For more options, visit this group at
>>> http://groups.google.com/group/dallasphp?hl=.

>>  --
>> You received this message because you are subscribed to the Google Groups
>> "DallasPHP" group.
>> To post to this group, send email to dallasphp@googlegroups.com.
>> To unsubscribe from this group, send email to
>> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
>> .
>> For more options, visit this group at
>> http://groups.google.com/group/dallasphp?hl=.

>  --
> You received this message because you are subscribed to the Google Groups
> "DallasPHP" group.
> To post to this group, send email to dallasphp@googlegroups.com.
> To unsubscribe from this group, send email to
> dallasphp+unsubscribe@googlegroups.com<dallasphp%2Bunsubscribe@googlegroups .com>
> .
> For more options, visit this group at
> http://groups.google.com/group/dallasphp?hl=en.


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.