Build-in CValidators auf Array-Elemente anwenden?

Hallo!

Ich speichere bestimmte Parameter als json-String in der Datenbank ab (Spalte "params" -> $this->params). Damit das Model auf die einzelnen Parameter Zugriff hat, und ich diese Parameter in bspw. einer ActiveForm wie andere Attribute auch verwenden möchte, bewerkstellige ich den Umgang mit den json-Strings derzeit wie folgt:

Im Model ($_params ist im Model als public declariert):


public function afterFind() {

    $this->_params = json_decode($this->params, true);       

    return true;

}


public function beforeSave() {

    if(parent::beforeSave()) {

        $this->params = json_encode($this->_params);

    }

}



Bis hierher funktioniert alles einwandfrei. Die einzelnen Parameter aus dem json-String sind nun über bswp. $this->_params[foo] ansprechbar.

Nun möchte ich jedoch auf diese einzelnen Parameter die Built-in Validatoren von CValidator anwenden…Möglich ist es, über “rules” im Model einen benutzerdefinierten Validator für das gesamte Array (das Attribut ‘_params’) anzugeben, in welchem ich von Hand alle einzelnen Parameter auf bestimmte Dinge überprüfen kann.

Versuche ich jedoch, einen Build-in Validator auf ein einzelnes Element von “_params” anzuwenden, zum Beispiel ‘required’, dann schlägt dies fehl!

So sehen die Rules dafür aus:


public function rules() {

    return array(

        array('_params[foo]', 'required'),

        array('_params', 'checkParams'),

    );

}


public function checkParams($attribute,$params) {   	

    if(!$this->_params[foo])

            $this->addError('_params[foo]','foo is required!');

}



Die untere Rule funktioniert problemlos, und ermöglicht mir, die einzelnen Elemente selbst zu prüfen und ggf. entsprechende Fehler zu erzeugen. Lieber wäre es mir jedoch, wenn ich für allgemeine Tests, wie z.B. ‘required’, die Build-in Validatoren nutzen könnte!

Die obere Regel schlägt jedoch fehl:


CException

Beschreibung


Eigenschaft "Model._params[foo] ist nicht definiert.


Quelldatei


yii\framework\db\ar\CActiveRecord.php(110)

Nun zu meiner Frage:

Kann ich die einzelnen Elemente auf irgendeine Art direkt bei den rules angeben, bzw. irgendwie aus einem eigenen Validator hinaus (2. rule, siehe oben) die Build-in Funktionen von CValidator ansprechen?

Oder gibt es gar einen ganz anderen Lösungsansatz für mein json "Problem"?

Vielen Dank für eure Hilfe!

Was du hier versuchst, würde ich mal in die Kategorie “unkonventionell” einordnen ;). Warum so umständlich?

rules() sind dafür gedacht, öffentliche Eigenschaften deines Models zu validieren. Also weder private Variablen (was evtl. Probleme mit den eingebauten Validatoren machen dürfte) noch einzelne Arrayelemente.

Was versuchst du denn mit dem json-codierten String zu bezwecken?

Die json-Strings deshalb, weil in der ensprechenden MySQL Tabelle in einer Spalte "params" eine nicht definierte Anzahl an Parametern gehalten werden soll. Anzahl sowie Typ der einzelnen Parameter, hängen von mehreren Faktoren ab.

Hättest du denn hierfür einen anderen Ansatz parat? Die Lösung mit der Speicherung des gesamten "Parameter-Arrays" als json-String gefällt mir eigentlich ganz gut - mir geht es hier nur um die Verwirklichung der Validierung (welche ich ja problemlos mit einem eigenen Validator bewerkstelligen kann - hier müsste ich nur auch die Built-in Validatoren selber nachbauen).

Danke dennoch für deine Antwort…:wink:

Ich seh den Vorteil von JSON hier zwar nicht (ist ja kein “natives” PHP-Format, du musst also ständig vor und zurück umwandeln, wenn du schreibst/liest) aber wenn du das für sinnvoll erachtest :). Ich hätte vermutlich mein DB-Schema nochmal unter die Lupe genommen. Gibt ja noch andere Wege, dynamische Attribute in einer relationalen DB zu halten.

Zum Thema Validierung nochmal: Die ist ja dafür da, öffentliche Attribute mit Regeln zu versehen und dem Benutzer für genau dieses Attribut im Formular bei Bedarf eine entsprechende Fehlermeldung anzuzeigen.

Du machst hier was ganz anderes: Du baust ein privates Array zusammen und möchtest das irgendwie prüfen. Aber was soll mit dem Fehler passieren, den du z…B. "_param[foo]" zuweist? Wo soll der angezeigt werden? Es gibt kein Formularfeld für "_param[foo]".

Hier seh ich den prinzipiellen Bruch, wie Modelvalidierung in Yii gedacht ist.

Das stimmt nicht ganz, alle Parameter werden vom User über ein Formular eingegeben, das ActiveForm mit den "festen" Attributen wird je nach Fall dynamisch um weitere Felder erweitert. Es gibt also im ActiveForm Felder für bspw. "_param[foo]", welche ich genauso behandeln möchte, wie alle anderen Attribute auch (vorallem die Fehlererzeugung im Formular, um nichts anderes geht es eigentlich). Deswegen setze ich auch auf "rules"…

Du magst sicher recht haben, da gibt es auch Alternativen. Nun ist im Rahmen der Projektplanung nunmal festgelegt worden, dass Parameter als json gespeichert werden - das hat auch verschiedene gute Gründe :wink:

Die Validierung über rules funktioniert ja auch gut, solange ich eine eigene Funktion zur Validierung angebe, in welcher ich die Elemente einzeln prüfe. Angesichts dessen, dass die Anzahl, Art und Validierungsregeln sowieso fallweise verschieden sind, komme ich da sowieso nicht drum herum. Ich wollte lediglich für einige "Parameter", welche immer vorkommen, die eingebauten Validatoren nutzen.

Also falls du jetzt keine konkreten Tips/Vorschläge dazu hast, muss ich erstmal damit leben. Danke trotzdem, für deine Hilfe! =)