Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Twig Instanceof Laravel Package

lelyfoto/twig-instanceof

Twig extension that adds an instanceof test, letting templates check whether a value is an instance of a given class or interface. Lightweight and easy to register for cleaner, type-aware Twig conditionals.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package with Composer:

composer require lelyfoto/twig-instanceof

Use v1.3 or later. v1.3 adds a return type that fixes a PHP deprecation notice and adds Symfony 8 support, so it is the safest baseline for current Laravel applications. If you are on an older pinned version and see deprecation noise in logs, upgrade first.

Laravel does not ship Twig by default, so this is usually used alongside TwigBridge. Register the package’s Twig extension class in config/twigbridge.php under the extensions array. Use the actual extension class from the package src/ directory:

// config/twigbridge.php
'extensions' => [
    // ...
    \Lelyfoto\TwigInstanceof\TwigInstanceofExtension::class,
],

Then clear cached config and compiled views:

php artisan config:clear
php artisan view:clear

Where to look first:

  • Package README.md for the exact syntax supported by your installed version.
  • Package src/ for the extension class name and compiler implementation.
  • Package tests/ for usage examples, especially quoting and class-name handling.
  • composer.lock to confirm you are on v1.3 or later (deprecation fix + Symfony 8 support).
  • Your app’s config/twigbridge.php to confirm the extension is registered.
  • resources/views for the first template where you want to branch on object type.

First practical use case: polymorphic view models or CMS blocks. A page receives a block object that may be an image block, video block, or text block. Instead of adding presenter booleans for every concrete type, pass a class map from PHP and branch in Twig:

return view('page.show', [
    'block' => $block,
    'types' => [
        'image' => \App\Blocks\ImageBlock::class,
        'video' => \App\Blocks\VideoBlock::class,
        'text'  => \App\Blocks\TextBlock::class,
    ],
]);
{% if block instanceof types.image %}
    {% include 'blocks/image.twig' with { block: block } only %}
{% elseif block instanceof types.video %}
    {% include 'blocks/video.twig' with { block: block } only %}
{% elseif block instanceof types.text %}
    {% include 'blocks/text.twig' with { block: block } only %}
{% else %}
    {% include 'blocks/fallback.twig' with { block: block } only %}
{% endif %}

This keeps class names out of templates and makes the template branch readable.

Implementation Patterns

Use a type map instead of hardcoded FQCNs in Twig. Pass class strings from the controller, view composer, or config. This avoids Twig string-escaping problems and makes class names testable:

'types' => [
    'renderable' => \App\Contracts\Renderable::class,
    'chart'      => \App\Widgets\ChartWidget::class,
],
{% if widget instanceof types.renderable %}
    {% include 'widgets/renderable.twig' with { widget: widget } only %}
{% endif %}

Prefer interface checks for stable template contracts. Checking an interface is usually more robust than checking a concrete class, especially if you use decorators, test doubles, or subclasses:

{% if payment instanceof types.payment_method %}
    {% include 'payments/method.twig' with { payment: payment } only %}
{% endif %}

Use instanceof before accessing subtype-specific fields. Twig will fail or return empty values when you access a property that only exists on one concrete type. Guard the branch first:

{% if widget instanceof types.chart %}
    <canvas data-series="{{ widget.series|json_encode }}"></canvas>
{% elseif widget instanceof types.table %}
    {% include 'widgets/table.twig' with { rows: widget.rows } only %}
{% endif %}

Wrap repeated block dispatch in a Twig macro. This keeps layout templates clean and centralizes the branching:

{% macro render_block(block, types) %}
    {% if block instanceof types.image %}
        {% include 'blocks/image.twig' with { block: block } only %}
    {% elseif block instanceof types.video %}
        {% include 'blocks/video.twig' with { block: block } only %}
    {% else %}
        {% include 'blocks/fallback.twig' with { block: block } only %}
    {% endif %}
{% endmacro %}
{{ _self.render_block(block, types) }}

Combine with Laravel presenters or view models. Keep business decisions in PHP, and use instanceof only for presentation-level dispatch:

class DashboardPresenter
{
    public function widgetTypes(): array
    {
        return [
            'chart' => ChartWidget::class,
            'table' => TableWidget::class,
        ];
    }
}

Test both sides of each branch. A feature test that renders the Twig view with one object per concrete type is usually enough:

$this->get('/dashboard')
    ->assertOk()
    ->assertSee('chart-widget');

For lower-level coverage, instantiate the Twig environment directly, add the extension, and render small fixture templates with mock objects.

Use instanceof as a temporary bridge, not a domain model. If the same type checks appear in many templates, move the decision into a presenter method such as widget->viewPartial() or a view component. The Twig expression is most useful for view-specific branching, not core business rules.

Gotchas and Tips

Pin v1.3 or later. v1.3 contains two changes worth having: a return type added to fix a PHP deprecation notice (PR #3), and Symfony 8 compatibility (PR #4). Neither is breaking, but staying on v1.2 or below means possible deprecation warnings and a hard incompatibility if your Laravel version pulls in Symfony 8 components. Check composer show lelyfoto/twig-instanceof after upgrading.

Verify the exact syntax for your installed version. This package adds an instanceof expression, but depending on the version it may register as an operator or a Twig test. The common form is:

{% if value instanceof types.someClass %}

If your installed version exposes a test-style syntax instead, it may look like:

{% if value is instanceof(types.someClass) %}

Check the package README and tests before standardizing examples across the codebase.

Typos in class names can fail silently. PHP instanceof checks against a string that does not resolve to a loaded class will usually evaluate as false rather than throwing a helpful template error. Keep class names in a PHP map built with ::class, and validate that map in a test.

Escape FQCNs if you hardcode them in Twig. Prefer passing class names from PHP. If you must inline them, remember backslashes and quoting:

{% if user instanceof 'App\\Models\\AdminUser' %}

Watch operator precedence. Mixing instanceof with not, and, and or can produce surprising results. Use parentheses:

{% if (item instanceof types.featured) and item.isVisible %}

Guard undefined or null values first. Do not rely on instanceof to protect against missing variables:

{% if block is defined and block is not null and block instanceof types.image %}

Clear Twig and Laravel caches after config or package changes. Twig compiles templates, and Laravel caches config. After adding or changing the extension registration, or after upgrading the package:

composer update lelyfoto/twig-instanceof
php artisan config:clear
php artisan view:clear

Be careful with decorators, proxies, and test doubles. instanceof checks the actual object class or implemented interfaces. If you wrap a model in a presenter or proxy, check the wrapper type or an interface, not the underlying Eloquent class.

Eloquent subclass checks are broad. Checking App\Models\User will also match AdminUser extends User. If you need exact-class behavior, add a dedicated PHP helper or presenter boolean rather than trying to express exact-class semantics in Twig.

Do not let user input choose the class name. Only pass class strings from trusted PHP maps. Never feed request input directly into an instanceof expression.

Treat the package as a small dependency with a fallback plan. It has low adoption and zero dependents, so pin the version, cover your templates with tests, and keep a fallback in mind. v1.3 is a maintenance release rather than a feature release, which is a good sign for stability but also means the surface area is unchanged. If needed, replace it with a small custom Twig extension exposing an instanceof test or function, or move the branching into presenter methods.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route