Working With View Composers in Sage 10

Originally published at: https://roots.io/working-with-composers-in-sage-10/

View Composers are new to Sage 10 and are based on Laravel’s View Composers, which are described this way: View composers are callbacks or class methods that are called when a view is rendered. If you have data that you want to be bound to a view each time that view is rendered, a view…

18 Likes

I’m trying to understand the “Get it from $data” part. What does this mean?:

“any variable [in $data array] available to that view is available to your Composer as well.”

Any variable created in a Composer file is added to $data array and it is available for the same Composer file where it was created. Is it?

Each Composer receives the $data variable, which is a keyed array. That Composer then adds keys and values to that array, and returns it. Each row in the array is then passed to the view, where each row is available as a variable with the name if that row’s key. Any views @included in that view will get the same data, which means their associated Composers will also get that data.

Let’s say I have a header.blade.php that looks like this:

// partials/header.blade.php
<header>
  {{ $title }}
  @include('partials.intro')
</header>

And its Composer has this:

// Composers/Partials/Header.php
public function with($data)
{
  return ['title' => 'Hello'];
}

So when the header is rendered, the $title variable will contain Hello.

The Composer for intro.blade.php could look like this:

// Composers/Partials/Intro.php
public function with($data)
{
  return ['intro' => $data['title'] . ' There'];
}

When the view intro.blade.php is rendered in header.blade.php, it will have access to a variable called $intro that contains Hello There. This is because when intro.blade.php is called in the context of header.blade.php, it has access to the same data that was passed to header.blade.php, which means its Composer also has access to that data, which is why we can concatenate that data in the Composer.

3 Likes

Yes! Thank you very much for this extra explanation. Very clear :+1:

1 Like

That sounds already very promising and thank you so much to continue the great work! Is there any ETA for sage 10?
However I’m quite sure that the forum will be full of questions regarding “Composer” vs “View Composers” as the terminology is easily confusing.

I’m sure we’d be open to consideration re: possible alternative names, so if you have some ideas I’d love to hear them!

Personally I feel fairly comfortable about addressing those issues if and when they come up, for two reasons:

  1. Laravel, as much larger organization, has been using this terminology for a while with no serious issues that I’m aware of, and as another PHP-based project they have definitely encountered composer the dependency manager.
  2. View Composers and composer the dependency manager have very, very different uses, so I feel like in most cases context will be sufficient to communicate which thing someone might be talking about.

There’s a bug in your Figure.php code:

return wp_get_attachment_image($image_id);

should be

return wp_get_attachment_image($data['image_id']);

In the article you use var_dump instad of @dump.
Is this a sign that @dump() and @debug are going away in sage 10, or am I reading too much into this?

You’re reading too much into this. I always forget about @dump because I’m so used to writing var_dump() all the time :frowning:

1 Like

Awesome! the reason I asked is that my @debug wasnt being parsed on the 10.0.0.dev branch, and I had a moment of concern. :ok_hand:

Just finished reading the article and would like to use sage 10 for my next project. Is the dev branch more or less ready for production work, and how can I install it?

That depends on how comfortable you feel troubleshooting it. I, and others, have used it at various stages for production sites (I launched two sites with an early development version of it).

It’s just a git repo, so:

$ git clone https://github.com/roots/sage.git
$ cd sage
$ git checkout 10.0.0-dev
$ cd site/web/app/themes
$ composer create-project roots/sage my-theme-name dev-10.0.0-dev
1 Like

In the previous Controller setup, I made extensive use of the App controller, so my template could parse an ACF flexible layout field and import other partials based on the name of the flexible component.

@alwaysblank With View Composers being tied to views, is there no way for a Template file to access the ACF data anymore?

I’m not 100% sure I understand your use case, but I think there are two things to address here:

  1. With Controller, data could only come from two sources: App and WhateverTemplateMatches (unless you enabled the tree, and your template got everything). With Composers, templates inherit whatever data is applicable to them, and their ancestors. (See this example earlier in the thread: Working With View Composers in Sage 10)

  2. Generally your templates shouldn’t be doing any parsing: They should only display the data given to them. If data needs to be parsed, you should do that in a Composer that will be passing data to the template in question. Keep in mind that because Composers inherit from all their ancestors, a lot of data is potentially available. If you want to replicate the App controller, you could just attach a Composer to your base layout: All data that Composer returns would be available in (essentially) all your templates, because everything is @extending that layout and hence receiving its data. Child composers also receive ancestor data, so you could load your ACF data in the layout controller, then ingest it in later component controllers and parse it as needed.

Looking forward to using v10, looks promising indeed! When do you expect an official release approx.? Was wondering how the migration from v9 to v10 should be done, any expected issues? Will be releasing a project I’m working on in a month or two, but would love to move to v10 in between if possible :slight_smile:

I’m trying to use $post in my composer but it keeps returning null. Is there something i should be doing?

Could you expand on what you mean?
Are you saying you’re trying to use the $post global that WordPress provides in post templates? Or are you trying to use your own variable, called $post?

I’m trying to use $post global.

I keep getting an error in my composer file when i use with($data, $view)
Warning: Declaration of App\Composers\....::with($data) should be compatible with Roots\Acorn\View\Composer::with() works when i remove $data & $view.

1 Like

$data and $view no longer have to be passed. They are automatically available as $this->data and $this->view if needed in a Composer.