root/trunk/patForms/Definition/Propel.php

Revision 346, 10.4 kB (checked in by sfuchs, 3 years ago)

Bug fixes and some clean-up in patForms/Propel integration stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
Line 
1 <?php
2 /**
3  * patForms_Definition for Propel integration
4  *
5  * Please note:
6  *
7  *        To use build-in patForms/Propel integration you have to build your
8  *        Propel classes with the following Propel build options enabled:
9  *
10  *         propel.addGenericAccessors = true
11  *         propel.addGenericMutators = true
12  *
13  *
14  * This class maps Creole types and Propel Validators to patForms_Elements
15  * and patForms_Rules. The class will automatically check for the existence
16  * of a patForms_Definition xml file and populate itself from the file if it'S
17  * present. If it's not present the class will lookup necessary data in the
18  * Propel peer class and write it to the xml file.
19  *
20  * This way the xml file will be created on the fly when the form definition
21  * is created for the first time. You can then tweak this file to match your
22  * needs. E.g. you'll want to change labels, descriptions, element types or
23  * the data fields that are used to populate select boxes for related tables
24  * (foreign keys).
25  *
26  * Please note: this class is currently php5 only since its solely used
27  * as a base class for patForms_Definitions_Propel in order to integrate
28  * patForms with Propel5 as a "rapid form solution".
29  *
30  * $Id$
31  *
32  * @author        Sven Fuchs <svenfuchs@artweb-design.de>
33  * @package        patForms
34  * @subpackage    Definition
35  * @license        LGPL
36  * @copyright    PHP Application Tools <http://www.php-tools.net>
37  */
38
39 /**
40  * requires the base class
41  */
42
43 require_once PATFORMS_INCLUDE_PATH . '/Definition.php';
44
45 /**
46  * requires the creole types
47  */
48
49 require_once 'creole/CreoleTypes.php';
50
51 /**
52  * patForms_Definition for Propel integration
53  *
54  * This class maps Creole types and Propel Validators to patForms_Elements
55  * and patForms_Rules. The class will automatically check for the existence
56  * of a patForms_Definition xml file and populate itself from the file if it
57  * exists. If it does not exist the class will lookup necessary data in the
58  * Propel peer class and write it to the xml file.
59  *
60  * This way the xml file will be created on the fly when the form definition
61  * is created for the first time. You can then tweak this file to match your
62  * needs. E.g. you'll want to change labels, descriptions, element types or
63  * the data fields that are used to populate select boxes for related tables
64  * (foreign keys).
65  *
66  * Please note: this class is currently php5 only since its solely used
67  * as a base class for patForms_Definitions_Propel in order to integrate
68  * patForms with Propel5 as a "rapid form solution".
69  *
70  * @author        Sven Fuchs <svenfuchs@artweb-design.de>
71  * @package        patForms
72  * @subpackage    Definition
73  * @license        LGPL
74  * @copyright    PHP Application Tools <http://www.php-tools.net>
75  */
76 class patForms_Definition_Propel extends patForms_Definition
77 {
78    /**
79     * Map Creole data types to patForm_Element types
80     *
81     * @static
82     * @access    private
83     */
84     private static $creoleTypeMap = array(
85         CreoleTypes::BOOLEAN        => 'Switch',    // BOOLEAN             = 1;
86         CreoleTypes::BIGINT         => 'Number',    // BIGINT             = 2;
87         CreoleTypes::SMALLINT       => 'Number',    // SMALLINT         = 3;
88         CreoleTypes::TINYINT        => 'Number',    // TINYINT             = 4;
89         CreoleTypes::INTEGER        => 'Number',    // INTEGER             = 5;
90         CreoleTypes::CHAR           => 'String',    // CHAR             = 6;
91         CreoleTypes::VARCHAR        => 'String',    // VARCHAR             = 7;
92         CreoleTypes::FLOAT          => 'Number',    // FLOAT             = 8;
93         CreoleTypes::DOUBLE         => 'Number',    // DOUBLE             = 9;
94         CreoleTypes::DATE           => 'Date',        // DATE             = 10;
95         CreoleTypes::TIME           => 'Date',        // TIME             = 11;
96         CreoleTypes::TIMESTAMP      => 'Date',        // TIMESTAMP         = 12;
97         CreoleTypes::VARBINARY      => 'String',    // VARBINARY         = 13;
98         CreoleTypes::NUMERIC        => 'Number',    // NUMERIC             = 14;
99         CreoleTypes::BLOB           => 'Text',        // BLOB             = 15;
100         CreoleTypes::CLOB           => 'Text',        // CLOB             = 16;
101         CreoleTypes::TEXT           => 'Text',        // TEXT             = 17;
102         CreoleTypes::LONGVARCHAR    => 'Text',        // LONGVARCHAR         = 17;
103         CreoleTypes::DECIMAL        => 'Number',    // DECIMAL             = 18;
104         CreoleTypes::REAL           => 'Number',    // REAL             = 19;
105         CreoleTypes::BINARY         => 'String',    // BINARY             = 20;
106         CreoleTypes::LONGVARBINARY    => 'Text',        // LONGVARBINARY     = 21;
107         CreoleTypes::YEAR           => 'Date',        // YEAR             = 22;
108         CreoleTypes::ARR               => 'String',
109         CreoleTypes::OTHER          => 'String'
110     );
111
112    /**
113     * Map Propel validator types to patForm_Rule classnames
114     *
115     * @static
116     * @access    private
117     */
118     private static $validatorTypeMap = array(
119         'unique'         => null,
120         'minLength'     => 'MinLength',
121         'maxLength'     => 'MaxLength',
122         'minValue'         => 'MinValue',
123         'maxValue'         => 'MaxValue',
124         'match'            => 'Match',
125         'notMatch'        => 'NotMatch',
126         'required'         => null, // will be done by the elements "required" attribute
127         'validValues'    => 'ValidValues',
128     );
129
130     /**
131      * Factory method to create a new patForms_Definition_Propel instance
132      *
133      * This method will check for the existence of a patForms_Definition xml
134      * file and populate itself from the file if it exists. If it does not
135      * exist the class will lookup necessary data in the Propel peer class
136      * and write it to the xml file.
137      *
138      * @static
139      * @access public
140      * @param  string  $conf     the name of the Propel class (e.g. 'Book') OR
141      *                            an assoc array of parameters:
142      *                          'name' => 'Book', // Propel object classname
143      *                          'filename'  => 'form.book.xml', // filename for xml definition
144      *                             'autoValidate' => 'save' // patForms autoValidate option
145      * @return object The patForms_Definition_Propel instance
146      * @todo   Probably check the mtime of the Propel basepeer class and
147      *         compare it with the mtime of the xml file if a parameter
148      *         pathToPropelBasepeer is provided. Defaults to: no check.
149      */
150     static public function create($conf)
151     {
152         if (!is_array($conf)) {
153             $conf = array(
154                 'name' => $conf,
155                 'filename' => 'form.' . $conf . '.xml',
156             );
157         }
158         extract($conf);
159
160         $conf['autoValidate'] = isset($autoValidate) ? $autoValidate : 'save';
161
162         $definition = new patForms_Definition_Propel($name, $conf);
163
164         if (file_exists($filename)) {
165             // load definition from xml file
166             $definition->load($filename);
167         } else {
168             // populate definition from table map and save it to xml file
169             $definition = self::populateFromPropel($definition, $conf);
170             $definition->save($filename);
171         }
172
173         return $definition;
174     }
175
176     /**
177      * Populates the definition with the properties from a Propel peer
178      *
179      * @access private
180      * @param  object $definition A patForms_Definition instance
181      * @param  array  $conf       An assoc array of parameters:
182      *                            'name' => 'book', // Propel object classname
183      * @return object The patForms_Definition instance
184      * @todo   Probably add an option to have "namespaced" request vars once
185      *         this feature is implemented in patForms
186      * @todo   Date type for patForms_Element_Date does not work
187      * @todo   Retrieve more specific data for the element attributes
188      */
189     private function populateFromPropel($definition, $conf)
190     {
191         extract($conf);
192
193         $dbname = constant($name . 'Peer::DATABASE_NAME');
194         $tablename = constant($name . 'Peer::TABLE_NAME');
195
196         $dbMap = Propel::getDatabaseMap($dbname);
197         $tableMap = $dbMap->getTable($tablename);
198         $cols = $tableMap->getColumns();
199
200         foreach($cols as $col) {
201
202             $elementName = $col->getPhpName();
203
204             if ($col->isPrimaryKey()) {
205                 $elementType = 'Hidden';
206             } else {
207                 $elementType = self::$creoleTypeMap[$col->getCreoleType()];
208             }
209
210             $attributes = self::getAttributesFor($elementType, $elementName);
211
212             switch ($col->getCreoleType()) {
213                 case CreoleTypes::BOOLEAN: {
214                     $attributes['value'] = 1;
215                     break;
216                 }
217                 case CreoleTypes::DATE: {
218                     $attributes['dateformat'] = 'Y-m-d';
219                     $attributes['presets'] = 'no';
220                     break;
221                 }
222                 case CreoleTypes::TIME: {
223                     $attributes['dateformat'] = 'Y-m-d';
224                     $attributes['presets'] = 'no';
225                     break;
226                 }
227                 case CreoleTypes::TIMESTAMP: {
228                     $attributes['dateformat'] = 'YmdHis';
229                     $attributes['presets'] = 'no';
230                     break;
231                 }
232                 case CreoleTypes::YEAR: {
233                     $attributes['dateformat'] = 'Y';
234                     $attributes['presets'] = 'no';
235                     break;
236                 }
237             }
238
239             if($col->isForeignKey()) {
240
241                 $relColname = $col->getRelatedColumnName();
242                 $relTablename = $col->getRelatedTableName();
243
244                 $tableMap = $dbMap->getTable($relTablename);
245                 $relClassname = $tableMap->getPhpName();
246                 $relColPhpname = $tableMap->getColumn($relColname)->getPhpname();
247
248                 $attributes['datasource'] = array (
249                     'type' => 'Propel',
250                     'peername' => $relClassname . 'Peer',
251                     'label' => array(
252                         'initial' => 'Please select one ...',
253                         'members' => array($relColPhpname),
254                         'mask' => '%s',
255                     ),
256                     'value' => array(
257                         'members' => array($relColPhpname),
258                         'mask' => '%s',
259                     ),
260                 );
261                 $elementType = 'Enum';
262             }
263
264             $rules = array();
265             if($col->hasValidators()) {
266                 foreach ($col->getValidators() as $validator) {
267                     $validatorName = $validator->getName();
268                     $validatorType = self::$validatorTypeMap[$validatorName];
269                     if (!is_null($validatorType)) {
270                         $rules[$validatorName] = array (
271                             'table' => $col->getTablename(),
272                             'col' => $col->getColumnName(),
273                             'name' => $validatorName,
274                             'type' => self::$validatorTypeMap[$validatorName],
275                             'value' => $validator->getValue(),
276                             'class' => $validator->getClass(),
277                             'message' => $validator->getMessage(),
278                         );
279                     }
280                 }
281             }
282
283             $definition->addElement($elementName, $elementType, $attributes, $rules);
284         }
285
286         return $definition;
287     }
288
289     static private function getAttributesFor($type, $name) {
290
291         $attributes = array('name'  => $name);
292         $defaultAttributes = self::getElementDefaultAttributes($type);
293
294         if ($type !== 'Hidden') {
295             $attributes['label'] = $name;
296             $attributes['title'] = $name;
297         }
298
299         if (self::hasDefaultAttribute('edit', $type)) {
300             $attributes['edit'] = $defaultAttributes['edit'];
301         }
302
303         if (self::hasDefaultAttribute('display', $type)) {
304             $attributes['display'] = 'yes';
305         }
306
307         // TODO Can we retrieve this info from the Column object?
308         if (self::hasDefaultAttribute('required', $type)) {
309             $attributes['required'] = 'yes';
310         }
311
312         return $attributes;
313     }
314
315     static private function hasDefaultAttribute($name, $type) {
316
317         return in_array($name, array_keys(self::getElementDefaultAttributes($type)));
318     }
319
320     static private function getElementDefaultAttributes($type) {
321
322         static $elements = array();
323
324         if (!isset($elements[$type])) {
325             $elements[$type] = patForms::createElement('', $type, null);
326         }
327
328         return $elements[$type]->getAttributes();
329     }
330 }
331
332 ?>
Note: See TracBrowser for help on using the browser.