Kategorien
Agavi Frameworks PHP XML

Eigene Configs in Agavi nutzen

Für diverse Aufgaben in größeren Projekten ist es notwendig, eigene XML-Konfigurationsdateien zu nutzen. Die Definition umfangreicher Einstellungen in der settings.xml wird schnell anstrengend und das Holen der Werte per AgaviConfig::get('setting.name', 'default'); unübersichtlich. Agavi bietet es aber an, eigene Konfigurationsdateien zu erstellen und diese nicht nur zu validieren, sondern auch zur Wiederverwendung zu cachen.
In der Agavi FAQ habe ich dazu mal ein Beispiel verfasst.

Einfach einen Config-Handler in der config_handlers.xml definieren:

<handler pattern="%core.config_dir%/project/foo/*.xml" class="AgaviReturnArrayConfigHandler" />

und dann direkt in den Actions, Views und Models benutzen:

if (!isset($config['baz']))
{
    throw new LogicException('baz is missing!');
}

if (isset($config['bars']))
{
    foreach ($config['bars'] as $foo => $data)
    {
        $this->doSomethingWithEach($foo, $data);
    }
}

Die XML-Datei für den obigen Code könnte beispielweise so aussehen:

<ae:configurations>
    <ae:configuration>
        <baz>asdf</baz>
        <foo>-1</foo>
        <bars>
            <some>...more data and xml...</some>
            <more>...more data and xml...</more>
            <deep>...more data and xml...</deep>
            <structs>...more data and xml...</structs>
        </bars>
    </ae:configuration>
    <ae:configuration environment="production.*">
        <baz>bleh</baz>
        <foo>1</foo>
    </ae:configuration>
</ae:configurations>

Gut zu erkennen ist der Vorteil eigener Configs: Man kann die Agavi-Features für Konfigurationsdateien nutzen und auf einfache Art und Weise environmentspezifische Einstellungen vornehmen (z.B. in „Production“ andere Werte für Logdateien, URLs oder Einstellungen nutzen als während der Entwicklung oder beim Testen).

Ebenfalls gut zu erkennen im PHP-Code ist, dass man lauter Abfragen über die Existenz bestimmer Elemente macht, die man sich mit vernünftiger Validierung sparen kann, da invalide XML-Dokumente gar nicht erst als korrekt angesehen werden von Agavi. Um seine XML-Strukturen zu validieren definiert man per validation Parameter ein XML-Schema und definiert noch gleich einen eigenen ConfigHandler, den man schreibt und per autoload.xml bekannt macht:

<handler pattern="%core.config_dir%/project/foo/*.foo.xml" class="FooDefinitionConfigHandler">
    <validation>%core.config_dir%/xsd/foo_definition.xsd</validation/>
</handler>

Der ConfigHandler könnte so beginnen:

class FooDefinitionConfigHandler extends AgaviXmlConfigHandler
{
    // notwendige Methoden implementieren und XML-Struktur validieren...
}

Für Beispiele einfach in die in Agavi verwendeten XSDs und entsprechende ConfigHandler sehen. Viel Spaß. :)

Kategorien
Apache Ruby On Rails Server

Nachfolgende Slashes mit mod_rewrite entfernen?

Mit diesem kleine Eintrag werden URLs mit einem Slash am Ende auf die gleiche URL ohne Slash am Ende geleitet. In meiner Rails Anwendung verursachten URLs mit einem Slash am Ende einen 403 – Forbidden.


RewriteEngine On
RewriteRule ^(.+)/$  $1 [R=301,L]

Kategorien
PHP PHPUnit

PHPUnit Manual – Sebastian Bergmann

Hier der komplette PHPUnit Guide um entsprechende Tests zu seiner Applikation zu schreiben.

PHPUnit Manual

Kategorien
MySQL PHP PHPUnit

Professionelle Softwareentwicklung mit PHP 5

Der ultimative Guide für Objektorientierung, Entwurfsmuster und Modellierung sowie fortgeschrittene Datenbankprogrammierung von Sebastian Bergmann

Professionelle Softwareentwicklung mit PHP 5

Kategorien
Management & Prozesse Scrum

Scrum Guide von Ken Schwaber

Hier der Scrum Guide von Ken Schwaber für alle die hinter die Kulissen der agilen Produktentwicklung sehen wollen.

Scrum Guide – Ken Schwaber als PDF

Kategorien
Deployment Linux Server Shell SVN Versionierung

.svn Verzeichnisse rekursiv aus Ordnern löschen

Folgender Kommandozeilen Befehl löscht alle .svn Verzeichnisse in einem Ordner.

Im Detail sucht das Kommando find
im aktuellen Ordner (.) rekursiv
nach Verzeichnissen (-type d)
mit dem Namen .svn (-name .svn)
und piped (|) diese Liste
nach xargs,
welches dann an erster Stelle (-0) der Liste
mit der Löschoperation (rm -rf) beginnt.


find . -type d -name .svn -print0 | xargs -0 rm -rf

Kategorien
Lighttpd Linux Server Shell

HTTP Authentifizierung mit Lighttpd

Um im schlanken Webserver Lighty eine HTTP Authentifizierung für bestimmte Verzeichnisse zu erzeugen, ist es notwendig, in der /etc/lighttpd/lighttpd.conf das Server-Modul mod_access und mod_auth zu aktivieren.


server.modules = (
                    "mod_access",
                    "mod_auth",
                    "mod_alias",
                    "mod_accesslog",
                    "mod_compress",
                    "mod_cgi",
                    "mod_fastcgi",
                    "mod_rewrite",
                    "mod_magnet",
                    "mod_redirect",
                    "mod_status",
                    )

Um ein Verzeichnis unterhalb eines bestehenden Webroots nun mit einer Authentifizierung zu schützen, tragen wir das in der /etc/lighttpd/vhosts.conf ein.


$HTTP["host"] =~ "(^|\.)domain\.tld$" {
        server.document-root = "/home/user/pages/"
        auth.backend = "htpasswd"
        auth.backend.htpasswd.userfile = "/home/user/passwd.txt"
        auth.require = ("/" => (
                                 "method" => "basic",
                                 "realm" => "admin",
                                 "require" => "valid-user"
                                 )
                         )
}

Zu guter Letzt benötigen wir noch die /home/user/passwd.txt die die betreffenden Authentifizierungsinfos bereit hält.


user:basic_encoded_password

Fortan ist der Ordner /home/user/pages/ passwortgeschützt.
Möchte man einen Unterordner passwortschützen, trägt man diesen statt des Slashes ein:


auth.require = ("/subdir/" => (
                                  "method"  => "basic",
                                  "realm"   => "admin",
                                  "require" => "valid-user"
                                  )
            )

Kategorien
ANT Deployment Linux Shell XML

Deployment mit ANT

ANT ist ein wunderbares Kommandozeilen-Tool mit dem man Deployment gerade auch von Webapplikationen automatisieren kann.

Ich benutze es um Entwicklungsstände in die Stage oder Liveumgebung auszuspielen.

Zur Konfiguration des Deploymentprozesses erzeugt man eine build.xml Datei, die alle nötigen Anweisungen enthält.

Folgende XML Datei erzeugt einen Backup-Ordner und kopiert die aktuelle Live-Applikation dort hinein.

Desweiteren erzeugt das Skript einen Datenbank Dump und kopiert diesen ebenfalls dorthin.

Danach wird der aktuelle Entwicklungsstand in den Live-Ordner kopiert.

Zu guter Letzt werden noch die Log- und Cache-Ordner geleert.


<project name="builder" default="build" basedir=".">
    <description>
        devel to live update including dbdump and clear cache
    </description>

    <!-- set global properties for this build -->
    <property name="devel" location="devel"/>
    <property name="live" location="live"/>
    <property name="backup" location="backup"/>

    <property name="db_host" value="localhost"/>
    <property name="db" value="databasename"/>
    <property name="db_user" value="databaseuser"/>
    <property name="db_pass" value="databasepassword"/>

    <target name="build">
        <!-- create the timestamp -->
        <tstamp/>

        <!-- create the backup dir -->
        <mkdir dir="${backup}_${DSTAMP}"/>

        <!-- dumb db to backup dir -->
        <echo message="create mysqldump"/>
        <exec executable="mysqldump" output="${backup}_${DSTAMP}/dump_${db}.sql">
            <arg value="${db}"/>
            <arg value="-u${db_user}"/>
            <arg value="-p${db_pass}"/>
        </exec>

        <!-- copy current live dir to backup dir -->
        <copy todir="${backup}_${DSTAMP}">
            <fileset dir="${live}"/>
        </copy>

        <!-- copy current devel dir to live dir -->
        <copy todir="${live}">
            <fileset dir="${devel}" excludes="**/*index.php"/><!-- beware overiding main config index.php -->
        </copy>

        <!-- delete cache/log files -->
        <echo message="cleanup cache/logs in backup/live"/>
        <delete includeemptydirs="true">
            <fileset dir="${backup}_${DSTAMP}/application/cache" includes="**/*"/>
            <fileset dir="${backup}_${DSTAMP}/application/logs" includes="**/*"/>
             <fileset dir="${live}/application/cache" includes="**/*"/>
            <fileset dir="${live}/application/logs" includes="**/*"/>
        </delete>
    </target>
</project>

Dieses Skript wird auf der Kommandozeile von Linux ausgeführt.

ANT sucht per default nach einer build.xml im ausführenden Ordner.


user@server:~/pages$ ant

Buildfile: build.xml

build:
    [mkdir] Created dir: /home/user/pages/backup_20091027
     [echo] create mysqldump
     [copy] Copying 1153 files to /home/user/pages/backup_20091027
     [copy] Copied 261 empty directories to 5 empty directories under /home/user/pages/backup_20091027
     [copy] Copying 50 files to /home/user/pages/live
     [echo] cleanup cache/logs in backup/live

BUILD SUCCESSFUL
Total time: 27 seconds

Kategorien
Frameworks Javascript Kohana PHP

der Kohana Script Collector Helper

Um modular und agil in Kohana zu entwickeln, wurde ein Skript Kollektor notwendig, der aus allen Controllern (Template- oder Standard-Controllern) Skripte (CSS, Javascript) sammeln kann.

Diese Scripte werden dann auf den jeweiligen Mastertemplates wieder an den richtigen Stellen eingebunden.
Dazu habe ich einen neuen Helper unter application/helpers/collector.php eingerichtet.


class Collector_Core
{
    /**
     * Arrays containing URL's to scripts/styles (fill with standards)
     * @var string
     */
    static protected $scripts       = array();
    static protected $styles        = array();

    /**
     * Adds a url to store
     * @param string $file the local path to file
     * @return void
     */
    static public function addJs($file)
    {
        self::$scripts[] = $file;
    }

    /**
     * Adds a url to store
     * @param string $file the local path to file
     * @return void
     */
    static public function addCss($file)
    {
        self::$styles[] = $file;
    }

    /**
     * Generates/renders collectors items
     * @param boolean      $print whether to echo the output or just return rendered string
     * @return string      the rendered output
     */
    static public function renderJs($print = false)
    {
        $scripts    = array_unique(self::$scripts);
        $output     = html::script($scripts);
        if ($print)
        {
            echo $output;
        }
        else
        {
            return $output;
        }
    }

    /**
     * Generates/renders collectors items
     * @param boolean      $print whether to echo the output or just return rendered string
     * @param string|array $media type for this style (all, screen, print, media)
     * @return string      the rendered output
     */
    static public function renderCss($print = false, $media = 'all')
    {
        $styles = array_unique(self::$styles);
        $output = html::stylesheet($styles, $media);
        if ($print)
        {
            echo $output;
        }
        else
        {
            return $output;
        }
    }
} // end of Collector_Core

Dieser Helper kann nun aus allen Controllern heraus befüllt werden.


class Welcome_Controller extends Template_Controller
{
    /**
     * set master template
     */
    public $template = 'master_default.tpl';

    /**
     * default constructor
     * @param void
     * @return void
     */
    public function __construct()
    {
        // load parent constructor
        parent::__construct();

        // collect scripts and styles
        collector::addCss('/css/fancybox');
        collector::addJs('/js/jquery.1.3.2');
        collector::addJs('/js/jquery.fancybox');
    }
    /** more code here */
} // end of Welcome_Controller

Nachdem nun alle relevanten Skripte eingesammelt wurden, kann man diese auf dem Template wieder ausgeben lassen.


<?php collector::renderCss(true, 'all'); ?>

<!-- html code here -->

<?php collector::renderJs(true); ?>

Der Kollektor sorgt dafür das keine doppelten Skripte geladen werden.

Kategorien
Agavi Frameworks

die inoffizielle Agavi FAQ

inoffizielle Agavi FAQ

Allen die immernoch sehnsüchtig auf eine offizielle Agavi Doku warten, sei hier die inoffizielle FAQ Variante von mivesto ans Herz gelegt.

mivesto.de/agavi/agavi-faq