2020-12-27 16:12 阅读 2

Reusing Criteria or Criteria filters.

I've found that if you want to reuse a criteria or just change the filter of one already initialized there is a problem because the $_is_prepared; property of the Criteria class is never set to false.

I think that it would be great if when changing a filter or setting a property the Criteria could be reinitialzed.

Thanks in advance.


  • 点赞
  • 写回答
  • 关注问题
  • 收藏
  • 复制链接分享

7条回答 默认 最新

  • weixin_39721370 weixin_39721370 2020-12-27 16:12

    Yes that's an excellent point. I think the query builder object would probably need to reset it.

    点赞 评论 复制链接分享
  • weixin_39721370 weixin_39721370 2020-12-27 16:12

    cristiandavidgm if you have a chance to test this out, that would be great. There is now a Reset method on the Criteria. This is called by QueryBuilder after it generates the SQL so you should be able to use it now without ever having to manually call reset - because normally the Prepare statement is only run when the SQL is being generated. But if you're doing something unusual, you can also just call Reset on the criteria and that sets _is_prepared back to false.

    It would be better as you mentioned that Reset is called any time a property is changed, but I don't think I can detect that with PHP. The __set() magic method can catch calls to virtual properties, but the criteria properties are all defined and so I don't know how to detect when they're changed. I'm open to suggestion though if anybody knows of a way?

    点赞 评论 复制链接分享
  • weixin_39604350 weixin_39604350 2020-12-27 16:12

    Sorry for closing and reopening, my bad :(

    Thank you very much for your answer :D, sorry for the delay.

    I will show you my scenario first: 1. I am using your awesome framework to serve as my RESTful api for an app made in sencha touch. 2. I have a reporter for a very customed query (which I hate actually, like a trillion joins):

    $repmjobitemses = $this->Phreezer->Query('RepmAssignedJobsReporter',$criteria);
    $output->rows = $repmjobitemses->ToObjectArray(true, $this->SimpleObjectParams());
    $output->totalResults = count($output->rows);
    $output->totalPages = 1;
    $output->pageSize = $output->totalResults;
    $output->currentPage = 1; 

    Sencha touch models do not trigger dependency loading so I have to send the whole model. For example I have to send the full record of a property instead of just his key because of this problem. There is logic in each property detail request so I cant load it on the query.

    So, I loop over the result:

    $criteriaProperty   = new RepmPropertiesCriteria();
    foreach ($wt as $n => $t) 
        /* Using Filters */
        //$cf = new CriteriaFilter('Propertyid', $t->jobTicketPropertyID );
        //$criteriaProperty->Filters = null;
        /* Without Using Filters */
        $criteriaProperty->Propertyid_Equals = $t->jobTicketPropertyID;
        $repmproperties     = $this->Phreezer->Query('RepmProperties',$criteriaProperty);
        $repmproperty       = $repmpropertieses->ToObjectArray(true, $this->SimpleObjectParams());

    Said that, This is my opinion:

    I think that the concept of using $_is_prepared to avoid recomputing the sql is excellent, and reseting the Criteria each query kind of broke it, Nevertheless the reset() solution works to me.

    I did the following last week:

    In the criteria Class I declared the __get and __set functions, but as the properties in the generated CriteriaDAO class are public I changed all the relevant properties to protected so every time I try to change a non-accesible property the __set function is fired.

    I also changed the Filters property to protected.

    As the __set function is fired I can set is_prepared to false every time a property change. I also set it tho false on AddFilter. I realize now that there are a lot of functions which should set it to false to like AddAnd or AddOr

    I hope it can help you to enhance this framework, which I think is fantastic.

    Thanks for your help Cristian David

    点赞 评论 复制链接分享
  • weixin_39721370 weixin_39721370 2020-12-27 16:12

    Very cool - I would be very interested to see and help promote your app if it's a public one - I really want to see more apps. I especially dig that you are using the back-end framework with a totally different front end. I am actually quite familiar with Sencha as well and the 2.0 version of Phreeze actually generated the app using ExtJS rather than bootstrap/backbone.

    I can see several possibilities to optimize your code for better scale, depending on your schema which obviously i don't know, but just looking at your code. Looping through and doing a query on each loop is something I usually try to avoid if at all possible because it's the dreaded N+1 query so it doesn't scale well.

    It could be possible to solve this with eager fetching - not sure though since you said your main query is already complicated with tons of joins. But, another possibility is to query all of the properties that you need and then group them as necessary in PHP. It's more work for the PHP code, but less work for the DB - which is easier to scale out:

    $ids = array();
    foreach ($wt as $n => $t) 
        $ids[] = $t->jobTicketPropertyID;
    $criteriaProperty->Propertyid_In = $ids;
    $repmproperties  = $this->Phreezer->Query('RepmProperties',$criteriaProperty)->ToObjectArray();
    foreach ($repmproperties as $repmproperty)
        // ... do the grouping via PHP ...

    Anyway possible helpful or not. As far as the __set and __get magic methods - I have considered going that route before but have resisted it in favor of "real" properties. But I'll take another look. I kinda don't like the Criteria objects have so many properties which are not always used.

    点赞 评论 复制链接分享
  • weixin_39721370 weixin_39721370 2020-12-27 16:12

    I just committed dd2262a9547db38938eef5c15af9e27d2358ecf3 which adds ClearFilters() method so you don't have to access the Filters property and set it to null.

    I was thinking about what should happen if you do re-use a criteria and I think probably the best thing is to keep any existing filters and let the user remove them if they want.

    点赞 评论 复制链接分享
  • weixin_39604350 weixin_39604350 2020-12-27 16:12

    Thank you very very much for your advice :+1: I will trying to implement it now.

    The app is not public, I feel so ungrateful :/.

    It is a mobile interface to an already built wep app. It is like an intranet. I chose your framework because of the fact that the DB schema was already built and I can not change it. It saved me a lot of time, Standard operations just worked out of the box. the only thing I had to change was auth but because of the platform auth system.

    By the way there is a sintaxis error on the generated code "AppBaseController.php" line 34, there is a parenthesis missing.

    if (!in_array($this->GetRouter()->GetUri(),array('login','loginform','logout'))

    As your fixes solve my problem I consider this thread closed.

    Cristian David.

    点赞 评论 复制链接分享
  • weixin_39721370 weixin_39721370 2020-12-27 16:12

    Thanks for the bug report. don't feel bad about the private app, phreeze is perfect for that kind of thing. I am really curious to see any apps with a customized UI so if you build a public one please share!

    点赞 评论 复制链接分享