Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Invokable view variable shouldn't be invoked #18

Open
weierophinney opened this issue Dec 31, 2019 · 4 comments
Open

Invokable view variable shouldn't be invoked #18

weierophinney opened this issue Dec 31, 2019 · 4 comments

Comments

@weierophinney
Copy link
Member

Hi,

when passing an invokable object to the view and trying to access it, the object is being invoked automatically which may not be intended.

// Controller action
public function testAction()
{
    $viewModel = new ViewModel();
    $viewModel->test = new class {
        public function __invoke(array $params) {}
        public function getName() {
            return 'test';
        }
    };
    return $viewModel;
}

// View
echo $this->test->getName();

Expected output:
test

Actual output:
Argument 1 passed to class@anonymous::__invoke() must be of the type array, none given

The reason is here (Zend/View/Variables.php):

public function offsetGet($key)
{
    if (!$this->offsetExists($key)) {
        if ($this->isStrict()) {
            trigger_error(sprintf(
                'View variable "%s" does not exist',
                $key
            ), E_USER_NOTICE);
        }
        return;
    }

    $return = parent::offsetGet($key);

    // If we have a closure/functor, invoke it, and return its return value
    if (is_object($return) && is_callable($return)) {
        $return = call_user_func($return);
    }

    return $return;
}

The process of passing and accessing variables should not take care of the kind of the variables passed.

I really don't get the point of invoking them automatically. If someone needs automatic invocation we have view helpers. My suggestion is to remove the automatic invocation or if you can't let go, add an interface check.


Originally posted by @antiphp at zendframework/zend-view#85

@weierophinney
Copy link
Member Author

Interestingly, that's a new feature, and it was done to allow defining helpers without requiring implementation of HelperInterface (see #60). As such, any such change at this point would be a BC break. We'll have to evaluate if this should be the behavior going forward, or something we want to revert and/or change with the next major version of zend-view.


Originally posted by @weierophinney at zendframework/zend-view#85 (comment)

@weierophinney
Copy link
Member Author

But how am I supposed to pass invokable objects then?

In short to show that my situation is not special (at least IMHO): I want to pass a command-like object to the view (ReplaceTranslation) and I want to show a preview of that command output (via its invokable method) as well as its name. I have more commands.

Workarounds I was thinking about:

  • pass just the return values of all required methods. Disadvantage: Usage of arrays again instead of objects
  • dump the object into an array-structure and pass it (optionally rebuild the object with that array-structure in the view again). Disadvantage: a) Arrays again b) Overhead c) Some object can't be rebuild easily
  • wrap the invokable object within another class. Disadvantage: a) Bad readability b) Wrapper has no real functionality, makes everything complicated
  • avoid invokable objects. Disdvantage: Loss of a widely used feature

All workarounds gave me a bad feeling.

I don't know how a case like this should be handled (because of BC) but I somehow think that the current implementation is wrong because I have no chance to pass invokable objects - that are not meant to be invoked automatically - in a clean way.


Originally posted by @antiphp at zendframework/zend-view#85 (comment)

@weierophinney
Copy link
Member Author

Am also having this problem. Had same ideas around workarounds, but all of these feel bad. I reversed engineered that some prior version ZF2 (beta most likely) had a getRawValue method which could have helped.


Originally posted by @roelvanduijnhoven at zendframework/zend-view#85 (comment)

@weierophinney
Copy link
Member Author

Though it does have some nice properties ;)!

In the end I chose to use the second approach, which was really not a big of a deal.


Originally posted by @roelvanduijnhoven at zendframework/zend-view#85 (comment)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant