A Twist on the MVC Skeleton


We use an enjoyable stack at our workplace; Zend/Laminas have always been integral to our SaaS. Onboarding new devs has always been challenging; it was rare to find folks that had previously used the combination of Laminas, Doctrine, Twig, Tailwind, and AlpineJS.

Rather than let them loose on our main codebase, I’d devised a sandbox to help them train and learn with micro-exercises.

I’ve also used it as a crucible to tie Laminas forms and AlpineJS models (work in progress).

I thought this would be useful for others and thought I’d take a sec to share!

Here’s a take on a Tailwind, Laminas, Doctrine, AlpineJS version of a skeleton, complete with Authentication and the dull boilerplate emails nobody likes to code. I hope it is of benefit to you as well!



Hi @Saeven,

I didn’t see doctrine migration integration in your project. How do you handle that in your project? Thanks!

1 Like

Hey @ALTAMASH80 - because of its intention, you can just run the command line tool to build the schema. Anything more advanced would be at the adopter’s discretion if they chose to use it as a base. Definitely open to PRs if you wanted to push something in!

Nice skeleton und easy to read, clean code. I like it.

I’m curious about the Twig statement. Is there a particular reason why you use a template engine? From my experience, using a template engine that went beyond Laminas View was always a drag. Once we set our coding standards high and agreed that only simple conditions, such as if- or switch-conditions or foreach loops, could be used in the templates, template engines that went beyond Laminas View were obsolete. The result was less memory consumption and a gain in speed.

1 Like

Thanks for the kind comments @ezkimo , appreciate you taking the time to leave feedback!

There’s nothing inherently wrong with standard templates. God knows I’ve written thousands of them.

In my opinion, Twig does lead to far less verbose templates that are “friendlier” in the opinion of the front-enders I hire. I do admit, that I can feel the cognitive noise lessen after a day of reviewing PRs laden with Twig templates versus those that are PHP-based. PHPStorm also has excellent Twig support!

Writing this here in Twig, I think I would still vote for it, though it may be a matter of taste:

{% for item in items %}
 * {{ item }}
{% else %}
  {%trans "Sorry, there were no items in your list" %}
{% endfor %}


<?php if ($items): ?>
  <?php foreach ($items as $item): ?>
    * <?php echo $item ?>
  <?php endforeach; ?>
<?php else: ?>
    <?php $this->translator->translate( 'Sorry, there were no items in your list'); ?>
<?php endif; ?>

The syntax is also very close to stuff my JS front-enders are used to, makes it culturally easier within the company to enforce separation of concerns.

As extra secret perk, the CI chain will alert me if someone adds {% autoescape off %} to their templates!!

Speaking to memory and speed, performance-wise, it hasn’t been a bottleneck. We run programs built on Laminas/Twig/Doctrine on PHP 7.4 that are backed by Memcached (on elasticache, all in AWS) and it is blistering fast under very heavy loads (400k registrants in an hour type of load). I’d rather scale horizontally than change templates at this point anyway :wink:

In any case, thanks! Take care!