Reusing/calling functions in viewcomposers

I’m looking for a way to run functions in composers but only once like this:

class Post extends \Roots\Acorn\View\Composer
{
    protected static $views = [
        '*'
    ];

    public function with()
    {
        return [
            'functionA' => $this->functionA(),
            'functionB' => $this->functionB(),
        ];
    }

    private function functionA()
    {
        $functionAReturn          = [];
        $functionAReturn['varA1'] = 'var 1';
        $functionAReturn['varA2'] = 'var 2';
        return $functionAReturn;
    }

    private function functionB()
    {
        $functionBReturn = [];
        if ($this->functionA()['VarA1'] === 'var 1') {
            $functionBReturn['varB1'] = 'var 1';
        } else {
            $functionBReturn['varB1'] = 'var A';
        }
        $functionBReturn['varB2'] = 'var B';
        return $functionBReturn;
    }
}

i want to output functionA in blade template, like {{ $functionA }} but also set functionB based on variables in functionA. Doing it like this means that functionA will be called twice though.

My closest solution for this is checking/setting $this->data or perhaps a private variable in functionA. It works, but it gets a little bloated and really not sure that data should be set like this.
An example:

class Post extends \Roots\Acorn\View\Composer
{
    protected static $views = [
        '*'
    ];

    public function with()
    {
        return [
            'functionA' => $this->functionA(),
            'functionB' => $this->functionB(),
        ];
    }

    private function functionA()
    {
        if ($this->data->functionA) {
            return $this->data->functionA;
        }
        $functionAReturn          = [];
        $functionAReturn['varA1'] = 'var 1';
        $functionAReturn['varA2'] = 'var 2';
        $this->data->functionA    = $functionAReturn;
        return $functionAReturn;
    }

    private function functionB()
    {
        $functionBReturn = [];
        if ($this->functionA()['VarA1'] === 'var 1') {
            $functionBReturn['varB1'] = 'var 1';
        } else {
            $functionBReturn['varB1'] = 'var A';
        }
        $functionBReturn['varB2'] = 'var B';
        return $functionBReturn;
    }
}

Is this the way to go, or any other suggestions?

How are you calling it in your view?

You could always directly return $this to the with method so you can use all of the methods available in the Composer.

public function with()
{
    return [
        'example' => $this,
    ];
}

and then call it with $example->functionA() inside your view.

But I’m not 100% sure if this will solve your problem without seeing how you’re calling functionA and functionB in your view.

interesting, did not know that you could to this, but that wont help me in this situation though.
To simplify, imagine that functionB should output “Hi {name}” or “Hello {name}” based on variables in functionA, but i want to keep those separate and logic in composer. Kind of like this:

alternative 1:

<span>
@if($functionA['varA1'] === 'var1')
  Hi {{ $functionB['name'] }}
@else
  Hello {{ $functionB['name'] }}
@endif
</span>

alternative 2:

<span>{{ $functionB['greeting'] }} {{ $functionB['name'] }}</span> //greeting is set in composer, based on value of functionA['varA1']

Of course the logic is more complex than this in my use case, but hard to explain in a simple manner… :slight_smile:

This example is for Sage9 but I think sort-of-conditional Traits might be the answer here.

Cool example, but really not what i’m looking for. Thanks anyway!

My first recommendation would be to rewrite the logic of functionA() so that it idempotent and you can call it as many times as you like.

If that’s not possible, you might consider using a static variable inside of functionA() so that it returns the same value every time. A trivial example:

functionA() {
  static $return = null;
  if ($return === null) {
    $return = logic_that_must_run_only_once();
  }
  return $return;
}
1 Like