Contao 3 Erweiterung nach Contao 4 Bundle

Composer -> Packagist -> Contao Manager

Glen Langer

Contao Stammtisch Berlin (09.07.2017)

Version: 1.2.0 vom 23.08.2017

Quellen

  • Online Doku von Contao / Quellcode Contao
  • Erfahrung durch Ausprobieren

 

Lizenz

Creative Commons Lizenzvertrag
Dieses Werk ist lizenziert unter einer Creative Commons Namensnennung - Weitergabe unter gleichen Bedingungen 3.0 Deutschland Lizenz.

Über mich

Worum geht es?

Composer Konzept, Grundlage für:

Contao 3 Erweiterung kompatibel für Contao 4
(nur kurz und warum wir das nicht wollen sollen)

Contao 3 Erweiterung nach Contao 4 Bundle

Praxis, BackupDB Bundle

Composer Konzept

  • Namespace: Vendor\Erweiterungsname
  • Autoloading
  • Abhängigkeiten
  • Version (Tag, Semantische Versionierung) =>
  • Branch Version
  • Installationsziel der Erweiterung durch Composer

Semantische Versionierung

Beginnend mit Contao 4 wird die semantische Versionierung verwendet. Das ist auch bei Erweiterungen sehr wichtig.

   4   .   0   .   0    -  RC1
 Major   Minor   Bugfix   Pre-Release

Regeln

  • Bugfix-Releases dürfen nur rückwärts kompatible Fixes enthalten
  • Minor-Releases können rückwärts kompatible neue Features enthalten
  • Jede inkompatible API-Änderung muss als neue Major-Version veröffentlicht werden

Semantische Versionierung

API-Änderungen

Nicht jede rückwärts inkompatible Änderung ist auch eine API-Änderung!

API

  • Als "public" oder "protected" deklarierte Methoden in PHP-Klassen
  • Ausgenommen Methoden, die als @internal gekennzeichnet sind

Templates sind explizit nicht Teil der API und können sich daher auch in Minor- oder Bugfix-Versionen ändern, selbst wenn dadurch Stylesheet-Anpassungen notwendig werden.

GitHub Name, Packagist Name

Die Account Namen und Namen einer Erweiterung bei

GitHub, Packagist und in der composer.json

Beispiel für easyupdate3

  • GitHub Account: BugBuster1701
  • GitHub URL: .../BugBuster1701/contao-easyupdate3
  • Packagist Account: BugBuster , verbunden mit dem GitHub Account, dort freigegeben
  • composer.json Eintrag "name": bugbuster/easyupdate3
  • ergibt: composer require bugbuster/easyupdate3

Achtung: keine Großbuchstaben im composer.json Eintrag "name" verwenden, das akzeptiert Packagist.org nicht!

Type einer Erweiterung

  • contao-module
  • contao-bundle
  • contao-component
  • symfony-bundle

composer.json Auszug der eigenen Erweiterung:

{
  "name":"bugbuster/contao-statistic_group-bundle",
  "type":"contao-bundle",
  ...

Verzeichnisstruktur

Contao 3

src/
  assets/
  config/
  classes/
  dca/
  languages/
    de/
    en/
  models/
  modules/
  templates/
tests/
composer.json
README.md
CHANGELOG.md
.gitignore

Hier würde der Inhalt von "src" installiert werden nach system/modules/erweiterung/

Contao 4 Standard-Edition

src/
  Resources/
    contao/        <-- Bisherige Contao-Dateien
      config/
      classes/
      dca/
      languages/
        de/
        en/
      models/
      modules/
      templates/
    public/        <-- Öffentliche Ressourcen
  DemoBundle.php   <-- Bundle-Klasse für manuelle Registrierung
tests/
composer.json
README.md
CHANGELOG.md
.gitignore

Hier würde "src" installiert werden nach vendor/DeinVendorName/Erweiterungsname/src/

Contao 4 Managed-Edition

src/
  ContaoManager/
    Plugin.php   <-- Contao Manager Plugin für automatische Registrierung 
  Resources/
    contao/        
      config/
      classes/
      dca/
      languages/
        de/
        en/
      models/
      modules/
      templates/
    public/        
  DemoBundle.php   
tests/
composer.json    <-- zusätzlicher Eintrag
README.md
CHANGELOG.md
.gitignore

Hier würde "src" installiert werden nach vendor/DeinVendorName/Erweiterungsname/src/

Contao 4 Managed-Edition ++

src/
  ContaoManager/
    Plugin.php
  Controller/      <-- Routing Controller
  Resources/
    config/
      routing.yml  <-- Routing Definition
    contao/        
      config/
      classes/
      dca/
      languages/
        de/
        en/
      models/
      modules/
      templates/
    public/        
  DemoBundle.php   
tests/
composer.json
README.md
CHANGELOG.md
.gitignore

Hier würde "src" installiert werden nach vendor/DeinVendorName/Erweiterungsname/src/

Erweiterung für Contao 3 und 4

composer.json deiner Erweiterung nur Contao 3, Auszug

    "require": {
        "contao/core": ">=3.2",
        "contao-community-alliance/composer-plugin": "*"
},

wird nun zu:

Erweiterung für Contao 3 und 4

composer.json deiner Erweiterung Contao 3 und 4, Auszug

    "require": {
        "contao/core-bundle":"~3.2 || ~4.2",
        "contao-community-alliance/composer-plugin":"~2.4 || ~3.0"
},

Erweiterung nur für Contao 4

composer.json deiner Erweiterung nur Contao 4, Auszug

    "require": {
        "php": ">=5.6.0",
        "contao/core-bundle":"~4.4"
    },

PHP ab 5.6.0, Contao ab 4.4.0 und <5.0.0. Da "composer-plugin" hier nicht mehr angegeben, vom type: contao-bundle, auch wenn das hier nicht steht.

Contao 3 Erweiterung als Contao 4 Bundle umbauen

Änderungen außer an composer.json

  • verschieben der Dateien in neue Dateistruktur
  • Anpassungen von wenigen vorhandene Dateien
  • Neue Klasse je für Standard und Managed Edition

Anpassung Autoload(er)

  • autoload.php: löschen, Ersatz: composer.json
  • autoload.ini: löschen, Ersatz: Contao Manager Plugin
    bzw. Handarbeit bei Standard Edition

autoload.php Ersatz für Klassen

Auszug aus composer.json der eigenen Erweiterung

	"autoload": {
		"psr-4": {
			"Vendor\\DemoBundle\\": "src/"
		},
        "classmap": [
                   "src/Resources/contao/"
		],
		"exclude-from-classmap": [
                   "src/Resources/contao/config/",
                   "src/Resources/contao/dca/",
                   "src/Resources/contao/languages/",
                   "src/Resources/contao/templates/"
		]
},

Hier: "psr-4" für die neuen Symfony Klassen, "classmap" für die alten Contao Klassen.

autoload.ini Ersatz

  • Angabe der Ladereihenfolge über requires in der autoload.ini, "default" war:
requires[] = "core"
  • Standard Edition über Eintragungen in der AppKernel.php.
  • Managed Edition über Manager Plugin, mittels Definition(en).

Auszug daraus, die Erläuterung zum Plugin selbst folgt:

...
	->setLoadAfter(['Contao\CoreBundle\ContaoCoreBundle'])
...

Auch hier die Default Angabe, nach dem Contao Core (Bundle).

Und die Template Pfadangaben?

Durch die Dateistruktur:

Resources/contao/templates

werden Templates vom Contao Core dort gesucht und gefunden.

Anpassung config.php

Angaben zu Klassen absolut angeben

$GLOBALS['FE_MOD']['miscellaneous']['demo'] = 'Demo\Module';

nun:

$GLOBALS['FE_MOD']['miscellaneous']['demo'] = 'Vendor\Demo\Module';

Anpassung config.php

Angaben CSS/JS/Bilder aus dem public Verzeichnis

$GLOBALS['BE_MOD']['content']['demo'] = array
(
	'tables'     => array('tl_demo'),
	'stylesheet' => 'bundles/vendordemo/meine.css'
);
  • Name der Bundle-Klasse "VendorDemoBundle" definiert den Verzeichnisname.
  • Name ohne "Bundle" , Rest in Kleinbuchstaben.
  • Pfad unterhalb von web/
  • http://domain.de/bundles/vendordemo/meine.css

Neue Klasse für Standard Edition

  • Bundle Klasse für "Vendor\DemoBundle":
    src/VendorDemoBundle.php
<?php
namespace Vendor\DemoBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class VendorDemoBundle extends Bundle
{
}

Bundle Klasse registrieren

Einfügen in app/AppKernel.php folgende Zeile am Ende des Array $bundles:


new Vendor\DemoBundle\VendorDemoBundle(),

Cache leeren, neu anlegen lassen


bin/console cache:clear --env=prod --no-warmup
bin/console cache:warmup --env=prod

Aufruf https://deinedomain/contao/install
Datenbank Update durchführen

Neue Klasse für Managed Edition

  • Plugin Klasse für den Contao Manager, Variante 1:
    src/ContaoManager/Plugin.php
<?php
namespace Vendor\DemoBundle\ContaoManager;
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;

class Plugin implements BundlePluginInterface
{
    public function getBundles(ParserInterface $parser)
    {
        return [
            BundleConfig::create('Vendor\DemoBundle\VendorDemoBundle')
                ->setLoadAfter(['Contao\CoreBundle\ContaoCoreBundle'])
                ->setReplace(['demo']),
        ];
    }
}

Neue Klasse für Managed Edition

  • Plugin Klasse für den Contao Manager, Variante 2:
<?php
namespace Vendor\DemoBundle\ContaoManager;
use Contao\ManagerPlugin\Bundle\Config\BundleConfig;
use Contao\ManagerPlugin\Bundle\BundlePluginInterface;
use Contao\ManagerPlugin\Bundle\Parser\ParserInterface;
use Vendor\DemoBundle\VendorDemoBundle;
use Contao\CoreBundle\ContaoCoreBundle;

class Plugin implements BundlePluginInterface {
    public function getBundles(ParserInterface $parser) {
        return [
            BundleConfig::create(VendorDemoBundle::class)
                ->setLoadAfter([ContaoCoreBundle::class])
                ->setReplace(['demo'])
        ];
    }
}

Bundle Klasse registrieren

Auszug composer.json, eigene Erweiterung, Autoload und Plugin:


"autoload":{
    "psr-4": {
	  "Vendor\\DemoBundle\\": "src/"
    }
},
"extra":{
  "contao-manager-plugin": "Vendor\\DemoBundle\\ContaoManager\\Plugin"
}

Praxis

Beispiele anschauen,

Vergleich:
contao_xing (Contao 3) mit
contao-xing-bundle (Contao 4 Bundle)

Routing:
Visitors mit FE und BE Route contao-visitors-bundle

Umbau BackupDB

Aus Zeitgründen erfolgte der Umbau durch einen Pull-Request einer vorbereiteten Version.

Tipp: Installation direkt von GitHub

Bei Neuentwicklung, wenn kein Sync zu Packagist, Installation direkt von GitHub. Dazu in composer.json der Contao Installation einfügen:

    "repositories": [
            {
                "type": "vcs",
                "url": "https://github.com/VendorName/demo-bundle"
            }
        ],
    "require": {
        "vendor/demo-bundle": "dev-develop"
    },

Bedeutet: Installation der Erweiterung "vendor/demo-bundle",  des GitHub Users VendorName, desssen Repository "demo-bundle", aus dem Branch "develop".

Tipp: Installation direkt von Festplatte

Bei Neuentwicklung, bei keiner Nutzung von GitHub, in composer.json der Contao Installation einfügen:

    "repositories": [
            {
                "type": "path",
                "url": "../../contao_entwicklung/demo-bundle"
            }
        ],
    "require": {
        "vendor/demo-bundle": "*"
    },

Bedeutet: Installation der Erweiterung "vendor/demo-bundle", Source ist der relativer Pfad aus Sicht der Contao composer.json. Composer legt wenn möglich Symlinks dabei an, wenn man das nicht will, nach der "url" Zeile einfügen:

                        ...demo-bundle",
            "options": {
                "symlink": false
            }

Extension from scratch

Alternative zur schrittweisen Umwandlung:

  • komplett neu direkt als Symfony Bundle

Quellen dazu: 

 

Fragen?

PSR Autoloading?

Tilde ~ und Caret ^ bei Versionsangaben?

Angabe "::class"?

PHP Standards Recommendations

http://www.php-fig.org/

PSR-0: alter Autoloading Standard, deprecated

PSR-4: erweiterter Autoloading Standard

Beispiel:

Class.php mit "namespace Vendor\Demo\test;":

psr-0: { "Vendor\\Demo" : src/" } :
          src/Vendor/Name/test/Class.php

psr-4: { "Vendor\\Demo" : src/" } :
          src/test/Class.php

Tilde and caret version constraints in Composer

Tilde (~)

  • ~4.1.3 bedeutet >=4.1.3,<4.2.0,
  • ~4.1 bedeutet >=4.1.0,<5.0.0 (oft genutzt),
  • ~0.4 bedeutet >=0.4.0,<1.0.0,
  • ~4 bedeutet >=4.0.0,<5.0.0.

 

Tilde and caret version constraints in Composer

Caret (^)

  • ^4.1.3 bedeutet >=4.1.3,<5.0.0, (oft genutzt)
  • ^4.1 bedeutet >=4.1.0,<5.0.0, genauso wie ~4.1 aber:
  • ^0.4 bedeutet >=0.4.0,<0.5.0, unterschiedlich zu ~0.4 nützlich für abwärtskompatiblen Bereich
  • ^4 bedeutet >=4.0.0,<5.0.0 genauso wie ~4 und 4.*

 

Class name resolution via ::class

ClassName::class - vollständig qualifizierter Namen der Klasse ClassName. Beispiel:

<?php
namespace Name\Space;
class ClassName {}

echo ClassName::class;

Ausgabe:

Name\Space\ClassName

Happy Coding!

Contao Ninja

 

Aktuelle Version dieser Folien auf: docs.contao.ninja

(auch als PDF und später auch als Video)