Skip to content


Subversion checkout URL

You can clone with
Download ZIP


Model finders can no longer be invoked from within an instance method. #851

mikegreiling opened this Issue · 6 comments

5 participants


This bug was introduced in e73ffe6 (Issue #744)

Apparently, now that Model has both a __call() and __callStatic() method, when I attempt to invoke a finder from within an instance method of the model itself using the "syntactic magic" from Model's __callStatic(), it will go through the __call() method instead.


class Users extends \lithium\data\Model {
    public function getNext($entity, $token = null) {
        $conditions = [...];
        return static::first(compact('conditions'));

It invokes Model::__call() instead of Model::__callStatic() and I get the exception Unhandled method call 'first'.

If I define it this way, it'll work... but it's not ideal, and the magic method used to work just fine.

class Users extends \lithium\data\Model {
    public function getNext($entity, $token = null) {
        $conditions = [...];
        return static::find('first',compact('conditions'));

Related stackoverflow threads:


This is a known php bug, i already talked about it on IRC. Actually it's not really a bug but more of a design decision. Parent calls wouldn't work if this wasn't the case. What I did is move most of my finders to static methods with explicit names. This makes the code somewhat more readable. But it isn't a fix I know.


It's not a huge nuisance to change my function calls, but I guess my main point is that this was an unintended BC break... these calls did used to work at one point.

So I guess the debate is, is it preferable to revert this commit and retain the prior ability to call these magic "finder" methods from within a model's instance methods, or is it preferable to keep the feature(s) added by pull request #744?


The previous behavior didn't respect the separation of concerns. Imo this "PHP ambiguity issue" should be managed by the Model class. Why not overriding Model::__call in your base model class with something like this ?

public function __call($method, $params) {
    if ($method === 'all' || isset($this->_finders[$method]) {
        return $this->_callFinders($method, $params);
    return parent::__call($method, $params);

protected function _callFinders($method, $params) {
    $isFinder = isset($this->_finders[$method]);

    if ($isFinder && count($params) === 2 && is_array($params[1])) {
        $params = array($params[1] + array($method => $params[0]));

    if ($method === 'all' || $isFinder) {
        if ($params && !is_array($params[0])) {
            $params[0] = array('conditions' => static::key($params[0]));
        return static::find($method, $params ? $params[0] : array());
    throw new BadMethodCallException(...)

This should provide the behavior you're expecting imo.


If there's a simple work-around for this that doesn't add any overhead, that's fine. Strictly speaking, though, this is not a bug. The static keyword is only intended to be used in static contexts, so the fact that you're using it in a method (getNext()) that isn't statically-defined is wrong.


perhaps it's bad practice to use the static keyword here, though if I were to replace static::first() with Users::first() the issue still exists...

@mikegreiling mikegreiling reopened this

I fixed this issue in #1161 and made a pull request.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.