Search code examples
phpcakephpcakephp-2.1cakephp-model

Every model, similar code - better way? (CakePHP)


In nearly every model, I end up writing code similar to the below example code. It checks to see if options like limit, order, conditions...etc are sent and changes the query based on that.

Just seems like there MUST be a better way, since most of this stuff is duplicated over and over in many models. Maybe I can use a behavior? Or maybe something else I'm completely overlooking?

I feel like I've tried to reinvent the wheel as far as the model code is concerned, but I'd really like to know what the wheel IS - ie what do most people do to manage their model code? I assume it's "normal" for models to be similar like this? Looking for best practice for this overall "similar model code" concept.

//Restaurant model
function getRestaurants($opts = null) {

    //initialize
    $findType = 'all';
    $params['conditions'] = array();    

    //order
    $params['order'] = 'Restaurant.name ASC';
    if(!empty($opts['order'])) $params['order'] = $opts['order'];

    //limit
    if(!empty($opts['limit'])) {
        $params['limit'] = $opts['limit'];
        if($params['limit'] == 1) $findType = 'first';
    }

    /*... ETC ETC
    - can pass conditions, pricing, days open....etc
    - obviously some things are only for this model, but things like
      limit, order, conditions...etc are for all my models
    */

    //pagination
    $paginate = false;
    if(isset($opts['paginate'])) {
        if($opts['paginate']) {
            $paginate = true;
        }
    }

    //either return the paginate options just created
    if($paginate) {
        return $params;

    //or return the restaurant data found
    } else {
        $data = $this->find($findType, $params);
        return $data;
    }
}

In some, there are more complicated things like - whether or not to contain/join certain models based on an option sent...etc etc.

I'm trying to stick with the MVC concept and keep all my DB stuff in the models.


Solution

  • If the code is the same for all models you could use a behavior and simply attach it to the models and change the query using the beforeFind() callback.

    Putting the code into AppModel is also fine and calling it inside the beforeFilter() of the models that need it. But I think the behavior is less work to type. ;) So I would go for the behavior. If you need more fanciness like specific options for a model while having a set of defaults you could simply change the behavior to support that by merging options from a property of the model with the defaults in the behavior. If you would be more specific i could provide a better solution.

    And finally: There is no common or 100% right way to do it. I would always choose the solution that stays close to MVC and follows KIS.