Symfony Service ID dynamisch konfigurieren mittels Parameter

Wenn man gern in seiner Depnedency Injection Kofiguration (services.yml) die Service Injektionen dynamisch konfigurierbar machen will über die parameters.yml,

parameters:
    my_class: 'App\MyClass'

kann man dies mittels der Symfony Expression Language Komponente tun:

composer require symfony/expression-language

Dann kann man in der services.yml definieren:

services:
    App\Command\MyCommand:
      arguments:
        - '@=service(parameter("my_class"))'

Windows Composer Update Fatal error: Allowed memory size of 1610612736 bytes exhausted

Folgende Fehlermeldung hat mein Composer trotz unbegrenztem Speicher:

 composer update
 Loading composer repositories with package information
 Updating dependencies (including require-dev)

 VirtualAlloc() failed: [0x00000008] Zur Verarbeitung dieses Befehls sind nicht gen
 VirtualAlloc() failed: [0x00000008] Zur Verarbeitung dieses Befehls sind nicht gen

 Fatal error: Out of memory (allocated 1260388352) (tried to allocate 201326600 bytes) in phar://C:/ProgramData/ComposerSetup/bin/composer.phar/src/Composer/DependencyResolver/RuleSet.php on line 83

Wenn man unter Windows ein composer Update nicht mehr durchführen kann, obwohl man das Memory Limit auf unbegrenzt gesetzt hat, dann hat man ein Problem:

Das Windows-Xammp ist nur als 32 bit System erhältlich und kann nur 2GB Ram bereitstellen im Moment, eine weitere Erhöhung ist nicht möglich.

Die Lösung ist  Composer mit einem 64bit PHP auf der Konsole auszuführen (dies hat dann bis zu 4GB Memory).

  • Download von PHP x64 Version
  • entpacken und php.ini anlegen (umbennnen der php.ini-development)
  • memory Limit erhöhen in php.ini: memory_limit = -1
  • auf der Konsole ausführen:
"C:\php-7.2.12-nts-Win32-VC15-x64\php" C:\ProgramData\ComposerSetup\bin\composer.phar update

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. weiterlesen…

PHP encode String zu Extended ASCII 8bit 255 Zeichen

Um auch Umlaute in ein Bit darzustellen, kann man den erweiterten ASCII Zeichensatz verwenden mit 255 Zeichen, der auch Umlaute enthält wie ä, ö, ü und ß.

Um dieses zu nutzen, kann man die folgende Funktion nutzen:

/**
 * @param string $string
 * @return string
 */
protected function asciiEncodeString(string $string): string
{
    $sourceEncoding = mb_detect_encoding($string);
    $destinationEncoding = 'CP437'; // Extended ASCII - Codepage 437
    $string = iconv($sourceEncoding, $destinationEncoding, $string);
    return $string;
}

UDP mit PHP Nachrichten senden und empfangen Beispiel

Mit PHP kann man über UDP auf dem eigenen Rechner sehr einfach Packete verschicken. Um dies zu testen, braucht man einen Sender und einen Empfänger. In dem Biepsiel kommunizieren beider über die lokale IP auf Port 20010. Die Beispiele müssen auf der Konsole ausgeführt werden.

Sender:

<?php
$address = '127.0.0.1';
$port = 20010;
$beat_period = 1;

$fp = stream_socket_client("udp://$address:$port", $errno, $errstr);
if (!$fp) {
 die("ERROR: $errno - $errstr");
}

while (true) {
 $message = sprintf(
 '%s send: %s'. PHP_EOL,
 date('c'),
 rand(0, 1000000)
 );
 fwrite($fp, $message);
 echo $message;

 sleep($beat_period);
}

Empfänger:

<?php

$address = '127.0.0.1';
$port = 20010;

$socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
socket_bind($socket, $address, $port);

if ($socket === false) {
 throw new \RuntimeException(
 sprintf(
 'could not connect to socket address %s on port %s. Error: %s %s',
 $address,
 $port,
 socket_last_error(),
 socket_strerror(socket_last_error())
 )
 );
}

while (true){
 echo socket_read ($socket, 1024);
}

mehrer UDP Frames mit PHP parallel auslesen mit socket_select()

Man kann in PHP sehr schwer parallel Operationen ausführen, aber für das lesen von mehreren Sockets gibt es die socket_select() Funktion. Damit lassen sich mehrere Socket Verbindungen parallel auslesen.

In dem Beispiel werden 2 UDP Socket Verbindungen erstellt und gleichzeitig ausgelesen:

function createSocket(string $ip, int $port)
{
    $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP);
    //set non blocking read
    socket_set_option($socket, SOL_SOCKET, SO_REUSEADDR, 1);
    socket_bind($socket, $ip, $port);

    if ($socket === false) {
        throw new \RuntimeException(
            sprintf(
                'could not connect to socket address %s on port %s. Error: %s %s',
                $ip,
                $port,
                socket_last_error(),
                socket_strerror(socket_last_error())
                )
        );
    }
    return $socket;
}
function readSockets()
{
 $waitTimeoutSeconds = 1;

 $socket1 = $this->createSocket('127.0.0.1', 20001);
 $socket2 = $this->createSocket('127.0.0.1', 20002);

 $sockets['socket1'] = $socket1;
 $sockets['socket2'] = $socket2;

 $read = $sockets;
 $write = null;
 $except = null;

 if (socket_select($read, $write , $except, $waitTimeoutSeconds))
 {
 // loop through the sockets that showed activity
 if (isset($read['socket1'])) {
    // socket 1 got a message
    $content1 = socket_read ($socket1, 1024);
 }
 if (isset($read['socket2'])) {
    // socket 2 got a message
    $content2 = socket_read ($socket2, 1024);
 }

 } else {
 throw new \RuntimeException('could not read any socket');
 }

 socket_close($socket1);
 socket_close($socket2);
}

PHP XMLReader für sehr große Dateien Beispiel

Um mit PHP große XML Dateien auswerten zu können, muss man einen SAX Parser verwenden, der die XML Dateien von oben nach unten durchliest und nicht in ein Objekt umwandelt. Dafür ist der XMLReader von PHP vorgesehen.

Ein Beispiel:

$data = new Data();
$reader = new \XMLReader();
$reader->open($file);

while ($reader->read()) {
    if ($reader->nodeType == \XMLReader::ELEMENT) {
        switch ($reader->name) {
            case "tagName1" :
                $node = new \SimpleXMLElement($reader->readOuterXML());
                $attributes = $node->attributes();
                $entity = new Entity();
                $entity->setId($attributes['id']);
                $entity->setName($attributes['name']);
                $entity->setCode($attributes['code']);
                $data->addEntity($entity);

                break;

            case  "tagName2":
                $node = new \SimpleXMLElement($reader->readOuterXML());
                $attributes = $node->attributes();
                $entity = new OtherEntity();
                $entity->setId($attributes['id']);
                $entity->setName($attributes['name']);
                $entity->setCode($attributes['code']);
                $data->addOtherEntity($entity);

                break;
        }
    }
}

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…