Trait ReadOnly für Propel Objekte im Paket PropelHelper

Ich nutze jetzt schon seit einer Weile das Framework Propel ORM (Object-Relational Mapping) in der Version 2.x,  um Daten aus MySQL Datenbanken in PHP-Objekte umzuwandeln, damit zu arbeiten und diese auch wieder in Datenbanken zu speichern. Natürlich geht das auch mit anderen DBRM (Database Management System) wie beispielsweise PostgreSQL.

Nun möchte man jedoch manchmal mit schreibgeschützten Objekte arbeiten, also verhindern, dass diese Daten in der Datenbank manipulieren können. Die Gründe können vielseitig sein. Natürlich könnte man jetzt dem Datenbank User die Schreibrechte entziehen, jedoch ist das auch nicht immer der ideale Weg, da man (besonders bei Webspace Paketen) nur einen User zur Verfügung hat und die Rechte gar nicht ändern kann.

Generell bringt Propel hierfür auch bereits eine Lösung mit: Einfach in der Schema Datei schema.xml im Tag table das Attribut readOnly="true" setzen. Hier ein Beispiel:

<?xml version="1.0" encoding="utf-8"?>
<database name="test" defaultIdMethod="native">
    <table name="user" readOnly="true">
        <column name="id" type="integer" primaryKey="true" autoIncrement="true" />
        <column name="address_id" type="integer" />
        <column name="is_active" type="integer" />
        <column name="note" type="varchar" size="255" />
        <foreign-key foreignTable="user_address">
            <reference local="address_id" foreign="id" />
        </foreign-key>
    </table>
    <table name="user_address" readOnly="true">
        <column name="id" type="integer" primaryKey="true" autoIncrement="true" />
        <column name="country_id" type="integer" />
        <column name="is_valid" type="integer" />
        <column name="first_name" type="varchar" size="30" />
        <column name="last_name" type="varchar" size="30" />
        <column name="addition" type="varchar" size="60" />
        <column name="street" type="varchar" size="60" />
        <column name="zipcode" type="varchar" size="10" />
        <column name="city" type="varchar" size="50" />
        <foreign-key foreignTable="country">
            <reference local="country_id" foreign="id" />
        </foreign-key>
    </table>
    <table name="country" readOnly="true">
        <column name="id" type="integer" primaryKey="true" autoIncrement="true" />
        <column name="is_europe" type="integer" />
        <column name="is_eu" type="integer" />
        <column name="iso2" type="varchar" size="2" />
        <column name="iso3" type="varchar" size="3" />
        <column name="code" type="varchar" size="3" />
        <column name="value" type="varchar" size="60" />
    </table>
</database>

Das klappt soweit auch: Propel entfernt die zum speichern und löschen benötigten Methoden save() und delete() aus den Propel Objekt-Klassen. Allerdings hat Propel irgendwann auch diverse Setter-Methoden aus den ReadOnly Objekt-Klassen entfernt, was zu ungewünschten Nebenwirkungen geführt hat. Beispielsweise funktioniert danach das verknüpfen von Tabellen mittels joinWith() nicht mehr:

$users = UserQuery::create()
    ->joinWith('User.UserAddress')
    ->joinWith('UserAddress.Country')
    ->find()
;
if ($users) {
    foreach ($users as $user) {
        $firstName = $user->getUserAddress()->getFirstName();
        $country = $user->getUserAddress()->getCountry()->getValue();
    }
}

Die Abfrage funktioniert zwar, jedoch wird beim „befüllen“ (hydrate) des User Objektes in der Klasse Base\User dann folgende `BadMethodCallException` Exception geworfen:

Call to undefined method: setAddressId.


Daher habe ich mich für einen anderen Weg entschieden und nutze statt des Attributs readOnly="true" in der schema.xml stattdessen  einen Trait ReadOnly, den ich einfach nur in jeder Objekt-Klasse benutzen muss, die schreibgeschützt sein soll.

Da ich plane nach und nach mehrere Traits und Klassen zur Vereinfachung der Nutzung von Propel zu schreiben, habe ich gleich ein Git Repository PropelHelper angelegt und werde dieses pflegen. Gerne kann jeder sich das Repo klonen oder direkt über Composer einbinden:

Git:

# Repo klonen:
$ git clone git://github.com/dhm80/PropelHelper.git

# Oder als Submodul anlegen:
$ git submodule add git://github.com/dhm80/PropelHelper.git /path/to/PropelHelper

Composer:

Datei composer.json editieren (bzw. mit diesem Inhalt anlegen):

{
    "require": {
        "dhm80/propel-helper": "dev-master"
    }
}

Hier ein Beispiel, wie der Trait eingebunden wird:

<?php

use Base\Country as BaseCountry;
use PropelHelper\ReadOnly;

class Country extends BaseCountry
{
    use ReadOnly;
}

Das wars schon.

Ich hoffe der Beitrag hilft Euch und freue mich natürlich auf Euer Feedback.

Das könnte dich auch interessieren …

Eine Antwort

  1. Ansas sagt:

    Update: Sehr cool, mit dem letzten Commit im aktuellen Propel2 dev-master Zweig von gestern wurde das o. g. von mir berichtete Problem behoben und Tabellen mit readOnly="true" Attribut können nun wieder „normal“ genutzt werden, da die Methoden alle wieder da sind (allerdings als protected Methoden, damit diese nur intern von den Schema Klassen genutzt werden können, was ich für eine gute und richtige Idee halte).

Schreibe einen Kommentar

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Bitte beachte die Hinweise zum Datenschutz