Yii2 versus Symfony 4 – ein Framework Vergleich

Ich habe lange mit Yii und dem Symfony Framework gearbeitet und will versuchen im Folgenden die Unterschiede von beiden Frameworks aus Programmierer Sicht zu erläutern.

Konfiguration von Umgebungen

Beim Erstellen von Web-Anwendungen hat man typischer Weise mindestens 2 Umgebungen: Die Entwicklungsumgebung, auf der man Fehler sehen will und die Live Umgebung, wo dies nicht passieren soll. Dazu kommen Test-Umgebung zum Ausführen automatisierter Tests und vielleicht eine Staging Umgebung.

Symfony löst das sehr geschickt, mit .env Dateien und eigenen Ordnern innerhalb des Konfigurations-Ordners.

Bei Yii muss der Programmierer selber hand anlegen, um die richtige Konfiguration zu laden, es sind von Hause aus nur 3 (dev, prod, test) Umgebungen vorgsehen, danach wird es unübersichtlich.

Konsolen Commands

Konsolen Commands und normale Controller unterscheiden sich in Symfony komplett in Sachen Syntax, jedoch bieten beide dieselbe Funktionalität an.

Hier hat Yii den Vorteil, sich sehr änhlich zu verhalten und denselben Syntax für Controller zu verwenden.

 Datenbank Interaktion

Yii 2 setzt auf einen eigenen Datenbank Wrapper, mit dem Datenbankoperationen und Migrationen getätigt werden. Datenbanken müssen über Migrationen erstellt werden und daraus können dann die Entitäten Objekte generiert werden. Yii setzt auf das ActiveRecord Pattern, was aus Performancesicht leider nicht optimal ist im Verglech zum Repository Pattern von Symfony, da jedes Entitäten Objekt unnötigen Funktionalität mit sich herum schleppt. Auf der anderen Seite ist alles sehr zentral abgelegt in einer Datei, seien es nun Labels oder Fehlermeldungen für Formulare, Validatoren für einzelne Attribute oder Queries auf die Tabelle. Komfortabel ist die Möglichkeit pro Entität einen andere Datenbank-Verbindung zu benutzen. Die Daten können mit Hilfe der Gridview sehr einfach angezeigt werden.

Symfony setzt auf Doctrine als ORM Mapper und hat damit den Vorteil, dass Tabellen automatisch erzeugt werden anhand der Entitäten Definitionen und man einen weitaus größeren Funktionsumfang verwenden kann sowie mehr Auto-Completition in der IDE erhält aufgrund des objektorientierten Stils von Doctrine. Zum Anzeigen der Daten in einer Listview gibt es keine direkte Komponente, hier kann man beim Erstellen von Administrationsoberflächen auf das Sonata Projekt zurück greifen, mit dem erstklassige Backends erstellt werden können.

Code Generatoren

Yii besitzt einen sehr guten Code Generator namens Gii, mit dem neben den Standard Funktionen wie Model und Extensions Skeletons auch CRUD Oberflächen und Formulare sehr schön und schnell generiert werden können auf der Konsole und zusätzlich auch mit einem Web Frontend.

Symfony hat seit neustem das Symfony Maker Bundle, welches sich sehr schön anpassen lässt, aber nicht an die Funktionalität von Gii heran reicht.

Views

Yii besitzt von Hause keine Templating Engine, alles ist erlaubt und wird auch gemacht in der View, sie ist voller PHP, eigentlich ein Anti Pattern.

Symfony hat eine eigene, sehr schöne Templating Engine: Twig, mit der man sehr schön View und Applikations-Logik/Code trennen kann.

REST

Yii bringt eine ausgewöhlich einfache und umfangreiche REST Implemnetierung mit sich, mit der man sehr einfach REST Schnittstellen erstellen kann inklusive HATEOAS.

Symfony hat seine eigene FOSRest Extension, die aber nicht so elegant wie die von Yii ist. HATEOAS ist nicht verfügbar.

Testing

Yii besitzt sehr viel statische Methode Aufrufe, die erstmal schwierig zu testen sind.

Symfony benutzt Dependency Injection für alle Services und lässt sich ausgezeichnet testen.

Fazit:

Symfony ist eine professionelle Basis für große und zu testende Projekte. Yii ist sehr gut geeignet für schnell zu erstellende Prototypen und kleinere Projekte.

Twig Extension zum Sortieren von Entitäten per Datetime Property

Wenn man im Template eine Doctrine Collection sortieren will nach einem Zeitstempel (createdAt in dem Beispiel), sollte man dies eigentlich vorher machen.

Wenn dies nicht möglich ist, z.B. im Sonata Admin Bundle, dann kann man diese Twig Extension verwenden:

{% foo| sortByCreatedAt('asc') %}

Twig Extension Code:

<?php

namespace App\Twig;

use App\Entity\Tag;
use Doctrine\ORM\PersistentCollection;
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class AppExtension extends AbstractExtension
{
    public function getFilters()
    {
        return array(
            new TwigFilter('sortByCreatedAt', array($this, 'sortByCreatedAt')),
        );
    }

    /**
     * @param PersistentCollection $objects
     * @return mixed
     */
    public function sortByCreatedAt($objects, $direction = 'asc')
    {
        $objects = $objects->toArray();
        usort($objects, function ($a, $b) use($direction) {
            if ($direction === 'asc') {
                return $a->getCreatedAt() >  $b->getCreatedAt();
            } elseif ($direction === 'desc') {
                return $a->getCreatedAt() <  $b->getCreatedAt();
            } else {
                throw new \Exception('unknown sort direction');
            }

        });
        return $objects;
    }
}

Strato und MySQL: General error: 1709 Index column size too large. The maximum column size is 767 bytes.

Bei einem Kunden wurde mir folgende Fehlermeldung angezeigt, wenn ich versucht habe über Symfony die Datenbank erstellen zu lassen:

General error: 1709 Index column size too large. The maximum column size is 767 bytes.

Dies liegt daran, das Strato so komische Einstellung bei ihren Managed Hosting Packete wie z.B. das STRATO PowerWeb hat. Strato wird diese Einstellung leider nicht ändern, aber man kann in Symfony in der doctrine.yaml (config.yaml) das Charset ändern, dann funktioniert Symfony auch auf einem Strato Server:

doctrine:
    dbal:
        # configure these for your database server
        driver: 'pdo_mysql'
        server_version: '5.6'
        charset: utf8
        default_table_options:
            charset: utf8
            collate: utf8_general_ci

Symfony Security Passwörter hashen mit dem PasswordEncoder

Der PasswordEncoder des Symfony Frameworks ist sehr gut geeignet auch in Zukunft sichere Hashes von Passwörtern in der Datenbank zu speichern und zentral zu konfigurieren.

Das SecurityBundle muss ggf. nachinstalliert werden:

composer require symfony/security-bundle

Man legt dazu in der security.yaml fest, welchen Hashing Algorithmus man verwenden will für welche Entität:

security:
    encoders:
        App\Entity\User: bcrypt

Die Entität muss das UserInterface implementieren: weiterlesen…

Symfony 3 Test-Datenbank einrichten für Integration Tests

In Symofny wird automatisch beim Ausführen von Tests die  app/config/parameters_test.yml geladen.
Dort sollte dann eine andere Datenbank angegeben werden, der Einfachheit halber mit demselben Datenbank User:

database_host: same_as_dev
database_port: same_as_dev
database_name: test_db
database_user: same_as_dev
database_password: same_as_dev

Dann müssen auf der Konsole folgende Befehle ausgeführt werden:
Cache leeren:
php bin/console cache:clear –env=test

Datenbank erstellen
php bin/console doctrine:database:create –env=test

Tabellen erstellen
hp bin/console doctrine:schema:update –env=test –force

Dann könnne Fixtures geladen werden und Integration Tests geschrieben werden.

 

Syfmony 3.3. – Wie man ein Repository als Service injeziert mittels Dependency Injection

In Symfony 3 wird standardmäßig immer der EntityManager injected, um dann darüber das entsprechende Repository zur Verfügung zu bekommen.

Meistens wird aber nur genau ein Repository benötigt und der Code und die Tests werden aufgebläht.

Es gibt eine einfach Möglichkeit in der Configuration einen Service von einem Respository zu erstellen:

service.repository.name:
 class: 'AppBundle\Repository\MyEntity'
 factory: 'Doctrine\ORM\EntityManagerInterface:getRepository'
 arguments: ['AppBundle\Entity\MyEntity']

Projekt: baby-taschenrechner.de

Das gerade fertiggestellt Projekt baby-taschenrechner.de beschäftigt sich mit den Fragestellungen rund um die Entwicklung des eigenen Kindes:

  • Wie groß wird mein Kind werden in x-Jahren
  • Wie schwer wird mein Kind in x-Jahren
  • Ist mein Kind zu schwer/zu dünn
  • Welche Kleidergröße wird es wann tragen?

Die Webseite soll Eltern dabei helfen herauszufinden, wann sie welche Kleidergröße kaufen müssen, um im nahenden Winter/Sommer das passende zu Hause zu haben.

Eltern können so einschätzne, ob das Kind zu dünn oder zu dick ist  für ihr Alter/Größe/Gewicht-Verhältnis.

Für die Realiserung wurden folgende Technologien verwendet:

Symfony 3, Docker, MySQL, PHP, GIT, Google Material Design, Amazon AWS

Amazon automatische Preisanpassung Tool

Für einen Kunden habe ich gerade ein Tool entwickelt, mit dem man die Preise der eigenen Waren bei Amazon automatisch anpassen kann.Dabei werden die Angote der Konkurrenz analysiert nach Zustand der Ware und nach Seller Seriösität und dadurch ein fairer Preis bestimmt für die Ware. Es werden alle Daten, die über die API verfügbar sind für die Preisbestimmung mit herangezogen, wie z.B. Seller Feedback (Bewertungen des Händlers), ob Amazon selber verschickt, Versanddauer und vieles mehr.

Das Tool vergleicht optional die Preise zwischen den verschiedenen Amazon Plattformen in Europa (DE, UK, IT, ES, FR) aber auch Plattformen außerhalb Europas, wie Japan oder Amerika und händelt die unterschiedlichen Währungen.

Das Ergebnis kann direkt zu Amazon mittels der API geschickt werden und die Preise werden sofort geupdatet.

Amazon Preisanpassung

Screenshot Preisanpassungs Tool

 

Die Anwendung ist in PHP mit Symfony 3 geschrieben und hat ein Frontend mit Twitter Bootstrap 3 und eine MySQL Datenbank. Außerdem gibt es eine Vagrant Umgebung für die Entwicklung mit PHP7.1 und nginx. Ausgeführt werden kann das ganze mit einer einfachen Xampp Umgebung oder Vagrant Virtual Box beim Kunden lokal auf einem PC.

Falls sie auch Interesse an einem solchen Tool haben, könnne sie gern Kontakt aufnehmen.