SuperCRUDs

Hallo zusammen,

ich bin gerade dabei ein größeres Datenbankmodell zu entwickeln und gleichzeitig die CRUD templates etwas auszubauen.

Dazu würde mich eine rege Diskussion freuen, da ich bei vielen Punkten noch keine gute Idee habe.

Dazu noch vorweg: Es gibt sicherlich unterschiedliche Ansatzpunkte, viele werden wohl das Erstellen von CRUDs als einmalige Angelegenheit betrachten.

Allerdings gibt es auch Projekte, bei denen auch das Model zunächst einer größeren Entwicklung bedarf und zu Beginn des Projektes noch keine händischen Änderungen vorgenommen werden (sollen).

ich will keine eierlegende Wollmilchsau, sondern nur ein paar "convenience-addons".

Dann mal weiter zur Idee. Die nun folgende Beschreibung bezieht sich noch auf yiic, sollte aber mit gii analog funktionieren.

Ich habe das bestehende CrudCommand nach P2CrudCommand erweitert und die generateInputField() methode überschrieben.




    public function generateInputField($modelClass,$column) {


        // omit PK

        if($column->isPrimaryKey)

            return "''";


        // render checkbox

        else if($column->type==='boolean')

            return "CHtml::activeCheckBox(\$model,'{$column->name}')";


        // render relation dropdown

        else if($column->isForeignKey) {

            $model = new $modelClass;

            foreach($model->relations() AS $name => $relation) {

                if ($relation[2] == $column->name) {

                    return "CHtml::activeDropDownList(\$model,'{$column->name}', CHtml::listData({$relation[1]}::model()->findAll(), 'id', 'title'), array('prompt'=>'Select ...'));";

                }

            }

        }


        // render file autocomplete

        else if(stripos($column->name,'p2File')!==false) {

            return "P2Helper::widget('application.modules.p2.components.P2AutoComplete',

                array(

                'model' => \$model,

                'attribute' => '".$column->name."',

                'searchModel' => 'P2File',

                'mode' => P2AutoComplete::MODE_SELECT,

                'class' => 'ui-widget',)

            );";

        }


        // render textarea input (with RTE)

        else if(stripos($column->dbType,'text')!==false) {

            $code = "CHtml::activeTextArea(\$model,'{$column->name}',array('rows'=>6, 'cols'=>50));";


            // tiny addon

            if(stripos($column->name,'html')!==false)

                $code .= "\$this->widget('P2Editor',

                    array(

                        'name'=>'".$modelClass."_".$column->name."',

                        'type'=> Yii::app()->params['editor']['type'],

                        'height' => Yii::app()->params['editor']['height'],

                        'toolbar' => Yii::app()->params['editor']['toolbar'],

                        'config' => Yii::app()->params['editor']['config']

                    )

                );";

            return $code;

        }


        // render datepicker

        else if(stripos($column->dbType,'date')!==false) {

            $code = "P2Helper::widget('system.zii.widgets.jui.CJuiDatePicker',

              array(

                    'model'=> \$model,

                    'attribute'=> '{$column->name}',

                    'htmlOptions'=>array('size'=>10),

                    'options' => array(

                        'dateFormat' => 'js:$.datepicker.ISO_8601'

                    )

                   )

             );";

            return $code;

        }


        // render normal input

        else {

            if(preg_match('/^(password|pass|passwd|passcode)$/i',$column->name))

                $inputField='activePasswordField';

            else

                $inputField='activeTextField';


            if($column->type!=='string' || $column->size===null)

                return "CHtml::{$inputField}(\$model,'{$column->name}')";

            else {

                if(($size=$maxLength=$column->size)>60)

                    $size=60;

                return "CHtml::{$inputField}(\$model,'{$column->name}',array('size'=>$size,'maxlength'=>$maxLength))";

            }

        }

    }



Wie man sieht werden bei bestimmten Datentypen und/oder Feldnamen spezielle Inputs generiert. Das funktioniert soweit prima.

Auch die Relations, zumindest solange die BELONGS_TO sind, sind recht einfach über ein Dropdown abzubilden.

Ich habe auch mal diese Extension versucht: http://www.yiiframework.com/extension/relation/ aber bisher ohne den ganz großen Erfolg.

Anbei meine Vorschläge, welche UI-Komponenten im Idealfall zur Relation generiert werden sollen:

BELONGS_TO: Dropdown mit allen Einträgen aus der Fremdtabelle, wenn die Gegenseite HAS_ONE ist, dann wäre es schön, wenn man die Auswahl nur auf die verfügbaren Elemente einschränken würde.

HAS_MANY: Nur read-only Liste, mit Links zu den Einträgen (eventuell in der Sidebar, wenn überhaupt)

MANY_MANY: Checkboxliste/MultiselectListBox mit allen Einträgen der "Gegenseite". Speicherung der Daten über ein ActiveRecordBehavior?

So weit so gut, any comments?

Oder gibt es gar jemanden, der das schon geschrieben hat ;) ?

Grüße

schmunk

Ich bin sehr gespannt auf gii und werde mit Sicherheit einige Arbeit in (deutsche) Templates hinein stecken. Dest so flexibler das wird, um so mächtiger wird der Code Generator. Man könnte z.B. für jedes der oben erwähnte Feldtypen (int, varchar, text, etc.) einen eigenen Code-Snippet schreiben, wie dieses Element ‘generiert’ wird. Vor der Generierung wählt man aus der Anzahl der vorhandenden Templates aus und klickt sich seinen Kuchen quasi zusammen.

So in etwa wäre meine Vorstellung…

Wenn du das Relation Widget benutzt, probiere bitte mal diese (weitaus verbesserte) Version aus:

http://code.google.com/p/yii-user-management/source/browse/trunk/user/components/Relation.php

Bis auf deine Anforderung unter HAS_MANY sind alle Relationsarten bereits unterstützt, sogar einige mehr… schau dir die Datei einfach mal an, sie ist noch sehr übersichtlich und klein :)

Danke, das mach’ ich gleich mal.

Das mit den HAS_MANY ist mir jetzt auch klar: braucht man so eigentlich gar nicht.

Hey, und das hier brauch ich ja auch :)

http://code.google.com/p/yii-user-management/source/browse/trunk/user/components/CAdvancedArBehavior.php

Bisher läuft es wie geschmiert :lol: Sehr geile Komponente!

Ein update hätte ich, line 311:


$result = $this->_model->dbConnection->createCommand($sql)->queryAll();

Meine Models nehmen eine andere DB Connection, sollte aber universell funktionieren.

CAdvancedArBehavior braucht man nicht, aber es erleichtert den Umgang mit MANY_MANY relations sehr.

Viel Handarbeit wird da automatisiert bzw. in generischen Klassen gekapselt.

Wir können ja mal ein google code svn repository mit gii templates aufbauen, sobald gii raus ist

(ich würde gerne auf das erste release warten, damit man nichts umsonst programmiert).

So Ladies,

ich hätte mal die erste beta in unserem SVN.

Vorweg hier der Link, der das ganze in Englisch erklärt:

http://phundament.com/en_us/blog?postId=55&postName=en-blog-Super_CRUDs

Wie schon oben geschrieben habe ich das CRUD command aufgebohrt, so dass es mehrere InputFields und auch RelationFields erzeugen kann. Dazu kann man nun auch noch eine Konfiguration angeben, welche Einfluss auf das Layout nimmt, s. Link.

Ich weiß, dass das Entwicklungsparadigma eigentlich vorsieht, dass das Model eigentlich schon fertig ist, wenn man die CRUDs macht, aber genau das läuft in der Praxis meist doch etwas anders und ich will nicht die ganze Zeit damit verbringen immer wieder kleinere Anpassungen zu machen, z.B. mehrspaltiges Layout.

Die Relations werden über das Behavior und das Widget von thyseus implementiert. Das macht hier übrigens die Basisklasse ZaActiveRecord.

Soweit so gut, sollte out-of-the-box laufen, wenn man noch folgendes berücksichtigt.

  • MANY_TO_MANY Tabellen müssen in der alphabetisch korrekten Reihenfolge angegeben werden, also feature_product, statt product_feature

Ich kuck mal, dass das alles in der beta 9 mit funktionierendem Beispiel drin ist.

Wobei vieles auch schon in der beta 8 funktioniert.

Grüße

schmunk

Hey,

das ganze sieht sehr vielversprechend aus.

Funktioniert das p2model und p2crud auch ausserhalb einer phundament-Installation?

Wie wäre es, wenn wir diese Funktionalitäten mal in das gii einpflanzen? Ich denke da

an so eine gii template collection oder ähnliches…

@schmunk:

benutzt du irgendeinen Instant Messenger?