Yii 3.0 first impressions

Hello everyone and Happy New Year!

We are all greatful that the final version 3.0 of Yii is out. A big thanks to all the developers that made this possible.

I’m writing this to complain a bit. When the first stable release of the app template was released, I tried to install it locally using the existing Apache and PHP-FPM setup in my Linux machine. I discovered that it didn’t work right out of the box. I created an issue for that.

Just a couple of days ago when I saw that the final version of 3.0 was out, I was eager to try it locally again. I installed it under my user’s public_html folder, so the url was under the /~<username>/.... path. I had to add a setenv instruction for the APP_ENV in the public/index.php file to make it work (first issue above). After requesting the application from the browser, I got a 404 error. I modified my Apache’s document root and set it to that directory, so that the requested url would not be in a subpath of the url. It worked. I again created a new issue for this.

Where am I getting to? I’m disappointed, because I cannot get the app to work in a local LAMP installation. The documentation clearly states that only local installations by using PHP’s internal web server and docker are supported. What about the classic LAMP installations? These should be officially supported along with docker and PHP’s server. There are plenty of such LAMP installations out there and imagine if the person responsible for installing new applications would have to get familiarized with docker. Don’t get me wrong, docker is fine, but imagine for a developer (like me) that has maintained and installed many Yii 1.1 and 2.0 applications in the past, sees a growing wall between him and the new version of the framework. Why would the Yii developers choose such a path that the only viable installation method is via docker? Would it be such a hassle to support LAMP installations? Are the docker installations so perfect? Yes, docker is simple to install, install the app packages, pull a few images and you are there and it’s supposed to be a reproducable environment. But the way I see it, it’s just too much magic, and when you need to install a few PHP extensions or make adjustments to PHP’s ini file, the magic starts to fade away.

In the end, we will all have to get familiarized with docker (even us dinosaurs…), but imagine yourself if eg. Symfony or Laravel would not work out of the box in a classic LAMP installation.

Thank you all.

2 Likes

here, public/index.php:

// Run HTTP application runner
$runner = new HttpApplicationRunner(
    rootPath: $root,
    debug: Environment::appDebug(),
    checkEvents: Environment::appDebug(),
    
    // look here
    environment: Environment::appEnv(),

    temporaryErrorHandler: new ErrorHandler(
        new Logger(
            [
                (new FileTarget($root . '/runtime/logs/app-container-building.log'))->setLevels([
                    LogLevel::EMERGENCY,
                    LogLevel::ERROR,
                    LogLevel::WARNING,
                ]),
            ],
        ),
        new HtmlRenderer(),
    ),
);
$runner->run();

//Environment.php

    /**
     * @return non-empty-string
     */
    public static function appEnv(): string
    {
        /** @var non-empty-string */
        return self::$values['APP_ENV'];
    }

//and here

private static function setEnvironment(): void
    {
        $environment = self::getRawValue('APP_ENV');

        if (!in_array($environment, self::ENVIRONMENTS, true)) {
            if ($environment === null) {
                $message = 'APP_ENV environment variable is empty.';
            } else {
                $message = sprintf('APP_ENV="%s" environment is invalid.', $environment);
            }

            $message .= sprintf(' Valid values are "%s".', implode('", "', self::ENVIRONMENTS));

            throw new RuntimeException($message);
        }
     
        //look here
        self::$values['APP_ENV'] = $environment;
    }

//update here

   private static function setEnvironment(): void
    {
        $environment = self::getRawValue('APP_ENV');

        //add default value;
        if ($environment === null) {
            $environment = self::PROD;
        }

According to your wishes, just set a default value at will;

Thanks. We’ll fix this use case for sure. Need a bit more time to figure out how to do it best.

For example, sub-directories support isn’t there out of the box and is handled in a separate middleware to squeeze a bit more performance in the majority of cases.

And APP_ENV not being set by default has to do with security and safe defaults. This one I’ve figured out more or less.

1 Like

Was it fixed already in new version of web application template?

Nope. Haven’t found a good way for it yet.

Just my opinion. IMHO, yii3 is totally useless to most people without it supporting standard nginx+php-fpm. Maybe do some separate app ‘app-web-old’ or do it in ‘bad way’ for now. When you figure out a good way, you’ll just rewrite it. You’re losing developers by not releasing it ASAP

This is quite harsh and uncalled for @inwoker
The beauty of open source is you are free to work with whatever meets your expectations.

Getting the web stack you want to work is easy using docker if you really care to do it.

As a dev you are bound to struggle if you insist on holding onto what has been superseeded by better options or similar but preferred so rethink your very hard opinions and offer your solutions to fill in the gaps where needed rather than engaging with such negative energy.

Stay positive and be helpful.

IMHO

Docker is the state-of-the-art and I personally use Docker also for local development instead of Wampp, Xampp, Lamp etc. I dropped these technologies in 2020 and replaced them with Vagrant and later Docker.

But truth is that some hostings (or even internal web servers of customers) only offer a subfolder with centrally installed PHP and DB and asking them to allow for Docker is sometimes a dead-end. Hopefully their subfolders are available via subdomains, so that every app has its own Origin (useful for localStorage) and I am surprised this scenario is not supported by the Yii3 application. I will focus on this in my project as well, read the last paragraph.

My private concern is …

The modern verbose and component-based approach that is super universal for the first developer, but not really transparent when reverse-engineered by a new developer. IDE just does not navigate you to the definition of an object or variable, as the definition is unknown. The developer must find where the DI is coded, track it and hope that all the DI relations will be clear. Which it is tedious so step-debugging is a savior.

Reconciliation

We both need to accept the new situation or we can stay with Yii2 - it will be alive for many more years as there are many developers who will prefer standard MVC over the Yii3-style. I also need to find my way to Yii3 .

Suggestion to Yii3 team

Once you are happy with Yii3, let’s implement basic CRUD for handling users, their roles and permissions, translations and other basic stuff in a demo application. Currently the official demo application only prints a text. So I am trying to create and document something more complex (but yet imperfect I guess) here. This can be the template for basic information-systems which I often create. Now it is my studying project.

It is not an official demo application, it is a web application template. This is the official demo application that implements basic CRUD functionality for handling users, their roles, permissions, etc.

If you want to use an Apache or Nginx web server, take a look at the ‘Configuring web servers’ article.
I think the article about the shared hosting environment will also be helpful. Although it is written for the Yii 2 template, it can be adapted for Yii 3 by replacing the webroot project template with public.

In my opinion, Yii3 is one of the best modern web frameworks that adhere to software standards.
Laravel is modern but does not adhere to these standards, whereas Symfony adheres to them but is not modern.
In addition to providing the best implementation of a dependency injection container, authentication and authorisation, the system uses configuration rather than convention. This allows you to modify or replace any part of your application as required, eliminating the need for time-consuming searches through documentation. Third-party integrations can also be configured.

I wish the Yii3 team every success and all the best for the future.
You’re doing a great job!

1 Like

I’ve been using yii1 and yii2 since 2015. as day to day user and lover of this framework, and plus currently work on laravel codebases too.
It’s hard to talk about this V3 without talking about V2 and V1, cause everything we feel it’s relative to the previous versions and previous experiences with other codebases.

So lets me open this out for everyone to see:

What worked well for Yii1 and Yii2:

One truth that we can all agree on is: Yii1 it’s not a php modern approach in the code itself but it’s still modern on the way of thinking about a web application. It’s easy to code an api/web interface once you get familiar with. Recently i modernized some ui fragments using htmx + yii1 and it just works perfect with the standard renderPartial(even added a small trait function to allow rendering of multiple partials at the same request as htmx introduces nicely this pattern). This is empowering almost 10y maintaining and updating Yii based applications and never stepped on my shoe, never was a problem, never noticed a bug and never there was a point of debate of replacing Yii. That’s surely due to the quality of the PHP code produced on Yii on the past 10y and the hard working and validation on every line commited on both codebases, as a user of this framework i trust in every line of code produced by it.

What didn’t work well on (v1,v2):

The quality of extensions. As a Yii user i don’t want any kind of extensions on my apps cause it’s easy anyways to extend it with inheritance myself. Or even install a composer package that nicely solves what i want and port it nicely to Yii using a CComponent/Component in case of being a service or a standalone class/function that solves that particular problem to me.
It’s not a global truth but i feel Yii2 reached the fine spot where we actually don’t need any kind of extension to work with, so thats how i feel about it’s extension system didn’t catch up.
The documentation is awesome as a hard user, but as a newcomer it lacks real use cases examples.

I’ve been waiting to grab on my hands Yii3 for such a long time. I’m already asking for forgiveness for writing such a long text for first impression, but i think Yii deserves more than a 5 lines opinion.

First positive impressions

  1. FormModel works nicely, i personally like the Model approach to adding business logic and validating it. What i personally like to write is something like: SignInForm extends …Yii default form class and implement it nicely to keep my controllers out of trouble. Also it’s much more testable to write it in a Model which it’s easier to test/find extend. The annotations(Java like) approach works great for those coming from .NET and Java like enviroment(PHP → Java, Java → PHP) always felt very familiar to me.

  2. Folder structure, nothing to talk about didn’t change that much

  3. Middleware patterns are very familiar nowadays, in short words, it’s a functional way to solve problems and allow extensibility. It always come with a price of every middleware having to lookup and take care to not break/slow the entire application but it’s so easy to plug-and-play that worth the cost.

  4. Finally standarized responses as returns, that’s something that bothered me a bit on Yii2 and Yii1. Also for PHP 8 have this ResponseInterface as default on developing is just heaven. Also i don’t see a world beside command line controllers where responseFactory is not a default.

public function auth(ServerRequestInterface $request): ResponseInterface
{
    $response = $this->responseFactory->createResponse(); <- A better way that it could be written is ResponseFactory::create(); i don't see a point of having as state of $this
    $response->getBody()->write('Hi ' . $request->getAttribute('username')); <- love it
    return $response;
}
  1. Services being injected on constructors is something that we always hoped for but we already could make it on our own on Yii2 but seeing it as a standard, don’t need to think much to know that it will work. Btw i will miss the old Yii::$app->paymentSystem/Yii:app()->paymentSystem too, there is some value too to having it as a global singleton. Middleware pattern are a huge win and i don’t think someone will ever configure it globally to be honest…
 public function __construct(
        private ExtraDataStorage $extraDataStorage // Data storage is easy to test, and insert whenever i can. That's great
    )
    {

    }
  1. Packagist as default. We all know about it don’t need say anything to know it’s good to have it as default way to install things on our Yii3 apps.

  2. Routing, Yii1/Yii2 didn’t have nice defaults for routing, yii1 is one camelCase, yii2 is a modern approach but it does not hide index.php as default so to be honest it never was a strong point on neither versions. Now it basically functions as laravel route.php where we can hard code it the way we want. We need that on Yii2 to be honest :slight_smile:. I consider solved for Yii3 and can sleep peacefully implementing rest urls without pain.

  3. Migrations, not really differs that much from what we had to have an opinion about it :sweat:. And to be honest i didn’t write that much with it, i just hope that we had nice defaults like laravel blueprint for timestamps our to linking a table into another based on a relation:

just an example of what i mean:

 Schema::create('flights', function (Blueprint $table) {
            $table->id();
            $table->timestamps(); // creates a created_at, updated_at that we often need on many tables...
        });
  1. ViewRenderer finally we have the html separated from the controller. I hope the viewRenderer could grow to suit every MPA need for rendering html to browsers: like having theme(light/dark mode) built in and allowing rendering multiple partials at once in a single call.

  2. Widgets, not really changed. It feels like a Yii3 port of we had on Yii2.

First negative impressions

  1. It’s nice to have everything nice and organized per domain but small businesses we value more the hability to change things fast and with a certain level of misture between concepts(concepts that we often do not understand the domain very well). That’s not only a problem for Yii but for this whole domain driven concept.

  2. Security as default, that’s something that we miss on every Yii version. I would i want not to escape user input anyway? Should be the default to escape it. Every unsafe way to do things should be hidden by default to the developer. Instead of teaching on the docs how to secure a Yii application, should have how to disable these default guardrails.

  3. I miss the basic template, why would someone that’s someone on my team needs to learn so much to get start building? Laravel has a better DX when it comes to getting started. That’s something critical that should be fixed on the docs on how to get this thing running in less than 5 minutes.

  4. View injections, that’s a hard name for what we call on SPA applications to: Context. Whenever we need to pass properties we call prop and whenever we pass a huge amount of props and many views depend on it, we call it context. It’s far to hard to work with it, i can understand why the following example would not be something to be considered a better approach:

Somehere on the application struture core/context/ProfileContext.php


final class ProfileContext extends ViewRendererContext {
     public function __construct(public readonly ...$props, // even some service) // thats pseudo code to not exhaustively write the possible props
}

inside the view.php or any layout:

if (!$this->context instanceof ProfileContext) 
  throw new Error('This view template requires ProfileContext');

... the rest of the html
  1. Often widgets on Yii1/2/3 requires css and js to be shipped alongside the reusable widget. I wish we had that. In that way when rendering partials or entire page renders we can control better when the js/css would be loaded. That would help us to not have to write entire global css/js files that do not be needed to be used on most of the screens.
abstract public class Widget {
   public function registerAssets(): void;
}

There is some other considerations but the main ones are there.

Personally what i really think would help Yii3 adoption for current Yii1 and Yii2 users is mainly the creation of a micro framework that wires the Yii3 movable pieces on a opinated direction. I’m talking about having the config, assets, views, controllers, widgets. Having a WebController with all the things injected that we need for rendering html, ApiController for having the things that we need to develop smoothly an api. It still lacks good defaults.
It feels, don’t get me wrong, a framework to build a frameworks which it’s not.

1 Like

I can understand the frustration here. Docker is useful, but it shouldn’t feel like the only practical option for a framework that has been used so much with traditional LAMP setups. Having clear Apache and PHP-FPM instructions would make the move to Yii 3 much easier for developers coming from Yii 1 and 2.

1 Like

These instructions are already available for Yii 3; take a look at the ‘Configuring web servers’ article.
Please note that a link to these instructions can be found in the ‘Creating a project’ article.

I’m very sorry, but following the instructions in the link for configuring web servers, I get a 404 page. Here’s what I get after I put the app inside my user’s public html folder:

Does this look sane or developer friendly to you?

It’s the reason I haven’t look at Yii 3 yet, I’m happy with Yii 2 and if this doesn’t change, I will probably never work with it. I myself don’t care about Docker, Vagrant or all this stuff, I maintain my own installation which is pretty damn solid, know its pros and cons and I will not go that way if this is the expected way by the Yii devs.

Based on the screenshot you provided, I guess you did something like this:

  1. Copy the yii3 folder containing the Yii3 project to the public html folder
  2. Navigate to the URL http://localhost/yii3/public

What you have to do additionally:

  1. Configure localhost like this:
<VirtualHost *:80>
  # Set document root to be "app/public"
  DocumentRoot "path-to-you-public-html-folder/yii3/public"

  <Directory "path-to-you-public-html-folder/yii3/public">
    # use mod_rewrite for pretty URL support
    RewriteEngine on
    
    # do not allow accessing URLs with script name
    RewriteRule ^index.php/ - [L,R=404]
    
    # If a directory or a file exists, use the request directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # Otherwise forward the request to index.php
    RewriteRule . index.php
    
    SetEnv APP_ENV dev
  </Directory>
</VirtualHost>
  1. Restart the web server
  2. Navigate to the URL http://localhost