Weekly Snap: Puppet Security, InnoDB & Doctrine Configuration

20 – 24 February featured databases in the form of InnoDB table configuration and Doctrine nested sets, plus a Puppet security recommendation.
Ronny explained how to configure InnoDB tables correctly with the help of tools such as phpMyAdmin.
Continuing the database theme, Eric gave a quick rundown on applying nested sets in Doctrine 1.2 for those who are also running an older version.
Thomas recommended Puppet users to upgrade to 2.6.14 or 2.7.11 and protect themselves against security vulnerabilities.

Doctrine 1.2 und Nested Sets

Über Doctrine schreibe ich ja gerne mal was, so auch heute. Da Doctrine 2.2 die letzte aktuelle Version ist, hoffe ich, dass es noch andere gibt, die ältere Versionen einsetzen und folgende Informationen vielleicht nützlich finden.
Kindknoten hinzufügen
Ein Nested Set zu speichern, bei dem die Sortierung der Knoten der Reihenfolge entspricht, wie sie hinzugefügt werden, sieht auf den ersten Blick ganz einfach aus:


$node->getNode()->insertAsLastChildOf($parent);

Aber: Doctrine ändert bei diesem Funktionsaufruf automatisch die Grenzen der Teilmenge (links und rechts), ausgehend von $parent, in der Datenbank. Die Grenzen vom Objekt $parent werden aber nicht aktualisiert. Das führt dazu, dass neue Knoten nicht als letztes, sondern als erstes Kind hinzugefügt werden. Ein simples


$parent->refresh();

nach jeder Änderung, löst das Problem.
Teilbäume
Zum Abschluss, stell ich noch Code zur Verfügung, der einen Teilbaum aus einem Nested Set, mit dem Namen Tree, selektiert:


$table = Doctrine_Core::getTable('Tree');
$tree = $table->getTree();
$query = $table->createQuery('t, Tree p')
               ->select('t.*')
               ->orderBy('t.lft ASC')
               ->where('p.id = ?', $id)
               ->andWhere('t.root_id = p.root_id')
               ->andWhere('t.level >= p.level')
               ->andWhere('t.lft BETWEEN p.lft and p.rgt');
$tree->setBaseQuery($query);
$hierarchy = $tree->fetchTree();
$tree->resetBaseQuery();
Eric Lippmann
Eric Lippmann
Lead Senior Developer

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er sich für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.

Weekly Snap: OSDC CfP, App Store & Doctrine Tips with Xmas & Travel Fun

12 – 16 December offered help for a Mac App Store error and automated database generation, called out to speakers for the OSDC, and shared stories of a consultant’s travel nightmare as well as photos from the team Christmas dinner.
From afar, Julian found his own solution to a Mac App Store product distribution file error, which was preventing him from installing an app update for TweetDeck’. By looking in the log files, he could locate and delete the faulty file and its related cache files, to successfully install his new app and even post a a guide in the process.
Eric got straight to the point and showed us how to automatically generate a database with Doctrine. Equipped with YAML schema files and a script for Doctrine CLI, he gave an example generation of an SQLite database with process hierarchy.
Toby then shared a day in his life as a consultant on the road, giving hopeful applicants a taste of what not to expect on the job. Meanwhile, Pamela shared photos of the team’s self-made Christmas dinner at the ADKK (Academy of Cooking Art) in Fürth and also opened the OSDC 2012 Call for Papers.
As the name suggests, the Open Source Data Center Conference is dedicated to open source software in data centers and large IT environments. This year the event will be held on the 25 – 26 April, with a focus on agile infrastructures, and in particular dev-ops and methods, databases, as well as scalability and infrastructure. Interested speakers are welcome to submit their presentation ideas till 31 January 2012. But that’s not all – three intensive workshops on the conference eve are also available to choose from, on IPv6, OpenNebula, Puppet Configuration Management. Early birds can also profit from ticket specials till 15 February.

Automatische Datenbankgenerierung mit Doctrine


Die Doctrine CLI ist ein komfortables Mittel um sich z.B. Datenbank, Modelle, Tabellen und Daten automatisch erstellen zu lassen. Voraussetzung dafür ist ein entsprechendes Skript welches die Doctrine CLI aufruft und YAML Schema Dateien. Folgendes Szenario soll Prozesse in einer SQLite Datenbank hierarchisch ablegen.
Beispielumgebung unter /tmp/blog vorbereiten:


# cd /tmp
# mkdir blog
# cd blog
# mkdir lib
# wget http://www.doctrine-project.org/downloads/Doctrine-1.2.4.tgz
# tar xzf Doctrine-1.2.4.tgz -C lib
# mkdir sqlite models sql schema fixtures


Doctrine CLI Skript:


/tmp/blog# cat doctrine.php
<?php
$dir = realpath(dirname(__FILE__));
require_once($dir . '/lib/Doctrine-1.2.4/Doctrine.php');
spl_autoload_register(array('Doctrine', 'autoload'));
spl_autoload_register(array('Doctrine', 'modelsAutoload'));
Doctrine_Manager::connection(
    'sqlite:///' . $dir . DIRECTORY_SEPARATOR . 'sqlite' . DIRECTORY_SEPARATOR . 'data.db',
    'connection_name');
$manager = Doctrine_Manager::getInstance();
$manager->setAttribute(Doctrine::ATTR_MODEL_LOADING,
                       Doctrine::MODEL_LOADING_CONSERVATIVE);
Doctrine_Core::loadModels($dir . DIRECTORY_SEPARATOR . 'models');
$config = array(
    'models_path' => $dir . DIRECTORY_SEPARATOR . 'models',
    'sql_path' => $dir . DIRECTORY_SEPARATOR . 'sql',
    'yaml_schema_path' => $dir . DIRECTORY_SEPARATOR . 'schema',
    'data_fixtures_path' => $dir . DIRECTORY_SEPARATOR . 'fixtures');
$cli = new Doctrine_Cli($config);
$cli->run($_SERVER['argv']);

Doctrine erwartet oder schreibt jetzt Modelle im Ordner models, Beispieldaten in fixtures, Datenbankschema in schema und die Datenbank in sqlite/data.db.
Eine Liste von verfügbaren Kommandos erhält man, wenn man das Skript ohne Argumente aufruft:


/tmp/blog# php doctrine.php
Doctrine Command Line Interface
doctrine.php compile
doctrine.php generate-yaml-models
doctrine.php rebuild-db
doctrine.php load-data
...


Unsere Datenbank soll aus 2 Tabellen bestehen - einmal der Tabelle process, in der die Prozesse gespeichert werden und process_hierarchy, in der diese verschachtelt werden:


/tmp/blog# cat schema/schema.yml
---
# schema/schema.yml
# Global parameters
connection: connection_name
# Tables
Process:
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    name:
      type: string(255)
      notnull: true
  relations:
    Trees:
      type: many
      class: ProcessHierarchy
      local: id
      foreign: view_id
ProcessHierarchy:
  actAs:
    NestedSet:
      hasManyRoots: true
      rootColumnName: root_id
  columns:
    id:
      type: integer
      primary: true
      autoincrement: true
    process_id:
      type: integer
  relations:
    Process:
      local: process_id
      foreign: id


Beispieldaten:


/tmp/blog# cat fixtures/data.yml
---
# fixtures/data.yml
Process:
  order:
    name: Order
  logistics:
    name: Logistics
  support:
    name: Support
ProcessHierarchy:
  root:
    Process: order
    children:
      logistics:
        Process: logistics
        children:
          support:
            Process: support


Zum Abschluss erstellen wir die Datenbank:


/tmp/blog# php doctrine.php build-all-load
build-all-load - Generated models successfully from YAML schema
build-all-load - Successfully created database for connection named 'connection_name'
build-all-load - Created tables successfully
build-all-load - Data was successfully loaded
/tmp/blog# php doctrine.php dql "from ProcessHierarchy h join h.Process p"
dql - executing: "from ProcessHierarchy h join h.Process p" ()
dql -   id: '4'
dql -   process_id: '4'
dql -   root_id: '4'
dql -   lft: '1'
dql -   rgt: '6'
dql -   level: '0'
dql -   Process:
dql -     id: '4'
dql -     name: Order
dql - -
dql -   id: '5'
dql -   process_id: '5'
dql -   root_id: '4'
dql -   lft: '2'
dql -   rgt: '5'
dql -   level: '1'
dql -   Process:
dql -     id: '5'
dql -     name: Logistics
dql - -
dql -   id: '6'
dql -   process_id: '6'
dql -   root_id: '4'
dql -   lft: '3'
dql -   rgt: '4'
dql -   level: '2'
dql -   Process:
dql -     id: '6'
dql -     name: Support

Eric Lippmann
Eric Lippmann
Lead Senior Developer

Eric kam während seines ersten Lehrjahres zu NETWAYS und hat seine Ausbildung bereits 2011 sehr erfolgreich abgeschlossen. Seit Beginn arbeitet er in der Softwareentwicklung und dort an den unterschiedlichen NETWAYS Open Source Lösungen, insbesondere inGraph und im Icinga Team an Icinga Web. Darüber hinaus zeichnet er sich für viele Kundenentwicklungen in der Finanz- und Automobilbranche verantwortlich.

Doctrine für PHP


Bei Datenbankverbindungen in PHP gehen die Meinungen der Entwickler schnell auseinander. Jeder verwendet die schnellste Lösung oder schreibt schnell eine Klasse welche die wichtigsten Funktionen übernimmt. Mittlerweile stehen dem Entwickler ja drei native Schnittstellen zur Verfügung: mysql, mysqli und PDO – wobei jede Vor- und Nachteile aufweist. Und es gibt eine Reihe von Abstraktionsschichten welche das Auslesen und Bearbeiten von Datensätzen erleichtern sollen wie z.B. ADODB, Creole/Jargon oder die Tools um MDB2 auf PEAR. Allerdings deckt keines dieser Werkzeuge den gesamten Bereich richtig ab. Schemadateien müssen von Hand erzeugt werden, Mapper von PHP Objekten sind umständlich zu konfigurieren, initialer Datenimport muss von Hand erledigt werden und komplizierte Abfrageteile werden dann doch wieder in SQL realisiert.
Seit 2006 wird an dem ORM Tool Doctrine geschraubt welches seit September in einer stabilen major release vorliegt. Doctrine orientiert sich an Hibernate aus der Javawelt und an den Active Record Pattern von Ruby on Rails. Das tolle ist: Man schreibt fast (!) keine einzige Zeile SQL mehr.
Die Relationen aus der Datenbank werden auf verschiedene Arten in PHP Objekte übersetzt. Man kann entweder gleich PHP Klassen schreiben (Aus denen dann später auch das Datenbankmodell erzeugt werden kann), lässt sich die Klassen aus einer bestehenden Datenbank erzeugen oder schreibt das Modell in einer deskriptiven, Doctrine eigenen Sprache welche auf YAML basiert. Es ist auch möglich verschiedene Datenbanken in einem logischen Modell zu Verbinden. Selbst solche Strukturen verhalten sich in PHP völlig transparent.
Doctrine an sich besteht aus einer Reihe von Objekten wie Connections, Tables, Collections, Records, Queries. Letztere können durch eine eigene, an SQL angelehnte Sprache, abgefragt werden (Anlehnung an HQL von Hibernate: DQL). Alle diese Objekte folgen speziefischen Entwurfsmustern wie Singletons, Prototypes oder EventListeners und können dadurch einfach erweiter werden.
Für kleinere Projekte schießt man damit sicherlich mit Kanonen auf Spatzen, auch benötigt man etwas Einarbeitszeit um den Baukasten zu verstehen. PHP geht damit aber insgesamt einen großen Schritt in Richtung Enterprisesoftware. Orientiert sich ein geplantes Projekt in diese Richtung ist Doctrine sicherlich nicht verkehrt und nimmt für die Zukunft eine Menge Arbeit ab: Cheatsheet von Doctrine.

Marius Hein
Marius Hein
Head of Development

Marius Hein ist schon seit 2003 bei NETWAYS. Er hat hier seine Ausbildung zum Fachinformatiker absolviert, dann als Application Developer gearbeitet und ist nun Leiter der Softwareentwicklung. Ausserdem ist er Mitglied im Icinga Team und verantwortet dort das Icinga Web.