Author: annis
Date: 2010-04-29 10:07:41 +0200 (Thu, 29 Apr 2010)
New Revision: 29311

Added:
   
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationField.php
   
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationsContainerForm.php
   plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/
   plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/js/
   
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/js/ahDoctrineEasyEmbeddedRelationsPlugin.jQuery.js
Modified:
   plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/README
   
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/config/ahDoctrineEasyEmbeddedRelationsPluginConfiguration.class.php
   
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahBaseFormDoctrine.class.php
Log:
Merge branch 'master' into HEAD

Modified: plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/README
===================================================================
--- plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/README  2010-04-29 
07:45:22 UTC (rev 29310)
+++ plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/README  2010-04-29 
08:07:41 UTC (rev 29311)
@@ -34,13 +34,17 @@
           }
         }
 
-  * Change the parent class in `lib/form/doctrine/BaseFormDoctrine.class.php` 
to `ahBaseFormDoctrine `
+  * Change the parent class in `lib/form/doctrine/BaseFormDoctrine.class.php` 
to `ahBaseFormDoctrine`
 
         [php]
         abstract class BaseFormDoctrine extends ahBaseFormDoctrine
         {
           ...
         }
+  
+  * Publish the plugin assets
+  
+        symfony plugin:publish-assets
 
   * Clear your cache
 
@@ -84,6 +88,10 @@
           'newFormAfterExistingRelations' => false,
           'multipleNewForms'              => true,
           'newFormsInitialCount'          => 2,
+          'newFormsContainerForm'         => null, // pass BaseForm object 
here or we will create ahNewRelationsContainerForm
+          'newRelationButtonLabel'        => '+',
+          'newRelationAddByCloning'       => true,
+          'newRelationUseJSFramework'     => 'jQuery'
         ),
         '...' => array(
           ...
@@ -184,8 +192,16 @@
 
   * `multipleNewForms` (boolean, not required): set this option to true if you 
want to have multiple new related object forms
 
-  * `newFormsInitialCount`: (integer, not required, default: 1): number of new 
object forms initially displayed (you may insert/delete those forms dynamically 
using JavaScript, all submitted subforms will be processed and validated.)
+  * `newFormsInitialCount` (integer, not required, default: 1): number of new 
object forms initially displayed (you may insert/delete those forms dynamically 
using JavaScript, all submitted subforms will be processed and validated.)
 
+  * `newFormsContainerForm` (form object, not required): if not passed, plugin 
will create custom ahNewRelationsContainerForm form with a single 
`ahAddRelation` button below the new relation form(s)
+  
+  * `newRelationButtonLabel` (string, not required, default: '+'): label for 
the `ahAddRelation` new relation button; the setting is used only when the 
`newFormsContainerForm` option is empty.
+
+  * `newRelationAddByCloning` (boolean, not required, default: true): Should 
the plugin add new relation forms by cloning them client-side (with 
JavaScript). If set to false, you should add the behaviour yourself to the 
`ahAddRelation` form button. The setting is used only when the 
`newFormsContainerForm` option is empty.
+  
+  * `newRelationUseJSFramework` (string, not required, default: 'jQuery'): the 
JavaScript framework that should handle the client-side logic of the 
`ahAddRelation` new relation button to dynamically add new forms in the 
browser. There is currently only a jQuery version available but a MooTools 
version is on my TODO list. :)
+
 ## Questions, bugs, feature requests? ##
 
 I can be reached via e-mail: [email protected]

Modified: 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/config/ahDoctrineEasyEmbeddedRelationsPluginConfiguration.class.php
===================================================================
--- 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/config/ahDoctrineEasyEmbeddedRelationsPluginConfiguration.class.php
     2010-04-29 07:45:22 UTC (rev 29310)
+++ 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/config/ahDoctrineEasyEmbeddedRelationsPluginConfiguration.class.php
     2010-04-29 08:07:41 UTC (rev 29311)
@@ -6,7 +6,7 @@
  * @package     ahDoctrineEasyEmbeddedRelationsPlugin
  * @subpackage  config
  * @author      Daniel Lohse, Steve Guhr <[email protected]>
- * @version     SVN: $Id: PluginConfiguration.class.php 12675 2008-11-06 
08:07:42Z Kris.Wallsmith $
+ * @version     SVN: $Id: 
ahDoctrineEasyEmbeddedRelationsPluginConfiguration.class.php 136 2010-04-26 
21:16:52Z koto $
  */
 class ahDoctrineEasyEmbeddedRelationsPluginConfiguration extends 
sfPluginConfiguration
 {

Modified: 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahBaseFormDoctrine.class.php
===================================================================
--- 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahBaseFormDoctrine.class.php
   2010-04-29 07:45:22 UTC (rev 29310)
+++ 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahBaseFormDoctrine.class.php
   2010-04-29 08:07:41 UTC (rev 29311)
@@ -5,14 +5,38 @@
  *
  * @package    ahDoctrineEasyEmbeddedRelationsPlugin
  * @subpackage form
- * @author     Daniel Lohse, Steve Guhr <[email protected]>, Krzysztof 
Kotowicz <kkotowicz at gmail dot com>
+ * @author     Daniel Lohse <[email protected]>
+ * @author     Steve Guhr <[email protected]>
+ * @author     Krzysztof Kotowicz <kkotowicz at gmail dot com>
  */
 abstract class ahBaseFormDoctrine extends sfFormDoctrine
 {
   protected
     $scheduledForDeletion = array(), // related objects scheduled for deletion
-    $embedRelations = array();       // so we can check which relations are 
embedded in this form
+    $embedRelations = array(),       // so we can check which relations are 
embedded in this form
+    $defaultRelationSettings = array(
+        'considerNewFormEmptyFields' => array(),
+        'noNewForm' => false,
+        'newFormLabel' => null,
+        'newFormClass' => null,
+        'newFormClassArgs' => array(),
+        'formClass' => null,
+        'formClassArgs' => array(),
+        'displayEmptyRelations' => false,
+        'newFormAfterExistingRelations' => false,
+        'multipleNewForms' => false,
+        'newFormsInitialCount' => 1,
+        'newFormsContainerForm' => null, // pass BaseForm object here or we 
will create ahNewRelationsContainerForm
+        'newRelationButtonLabel' => '+',
+        'newRelationAddByCloning' => true,
+        'newRelationUseJSFramework' => 'jQuery'
+    );
 
+  protected function addDefaultRelationSettings(array $settings)
+  {
+    return array_merge($this->defaultRelationSettings, $settings);
+  }
+
   public function embedRelations(array $relations)
   {
     $this->embedRelations = $relations;
@@ -21,38 +45,46 @@
 
     foreach ($relations as $relationName => $relationSettings)
     {
+      $relationSettings = $this->addDefaultRelationSettings($relationSettings);
+
       $relation = $this->getObject()->getTable()->getRelation($relationName);
-      if (!isset($relationSettings['noNewForm']) || 
!$relationSettings['noNewForm'])
+      if (!$relationSettings['noNewForm'])
       {
+        $containerName = 'new_'.$relationName;
         if (($relation->isOneToOne() && 
!$this->getObject()->relatedExists($relationName)) || !$relation->isOneToOne())
         {
-          $formLabel = isset($relationSettings['newFormLabel']) ? 
$relationSettings['newFormLabel'] : null;
-          if (!empty($relationSettings['multipleNewForms'])) // allow multiple 
new forms for this relation
+          $formLabel = $relationSettings['newFormLabel'];
+          if ($relationSettings['multipleNewForms']) // allow multiple new 
forms for this relation
           {
-
-            $newFormsCount = !empty($relationSettings['newFormsInitialCount']) 
? $relationSettings['newFormsInitialCount'] : 1;
-
-            $subForm = new sfForm();
-            unset($subForm[sfForm::$CSRFFieldName]);
+            $newFormsCount = $relationSettings['newFormsInitialCount'];
+            
+            $subForm = $this->newFormsContainerFormFactory($relationSettings, 
$containerName);
             for ($i = 0; $i < $newFormsCount; $i++)
             {
-              // we need to create new forms with cloned object inside 
(otherwise only the last new values would be saved)
+              /*
+               * we need to create new forms with cloned object inside
+               * (otherwise only the last new values would be saved)
+               */
               $newForm = $this->embeddedFormFactory($relationName, 
$relationSettings, $relation, $i + 1);
               $subForm->embedForm($i, $newForm);
             }
             $subForm->getWidgetSchema()->setLabel($formLabel);
-            $this->embedForm('new_'.$relationName, $subForm);
+            $this->embedForm($containerName, $subForm);
           }
           else // just a single new form for this relation
           {
             $newForm = $this->embeddedFormFactory($relationName, 
$relationSettings, $relation, $formLabel);
-            $this->embedForm('new_'.$relationName, $newForm);
+            $this->embedForm($containerName, $newForm);
           }
         }
       }
-
-      $formClass = !isset($relationSettings['formClass']) ? null : 
$relationSettings['formClass'];
-      $formArgs = array_merge((!isset($relationSettings['formClassArgs']) ? 
array() : $relationSettings['formClassArgs']), 
array(array('ah_add_delete_checkbox' => true)));
+      
+      $formClass = $relationSettings['formClass'];
+      $formArgs = array_merge(
+        $relationSettings['formClassArgs'], 
+        array(array('ah_add_delete_checkbox' => true))
+      );
+      
       $this->embedRelation($relationName, $formClass, $formArgs);
 
       /*
@@ -67,14 +99,14 @@
           ((!$relation->isOneToOne()) && 
(count($this->getEmbeddedForm($relationName)->getEmbeddedForms()) === 0)) ||
           ($relation->isOneToOne() && 
$this->getEmbeddedForm($relationName)->isNew())
         ) &&
-        (!isset($relationSettings['displayEmptyRelations']) || 
!$relationSettings['displayEmptyRelations'])
+        (!$relationSettings['displayEmptyRelations'])
       )
       {
         unset($this[$relationName]);
       }
 
       if (
-        isset($relationSettings['newFormAfterExistingRelations']) && 
$relationSettings['newFormAfterExistingRelations'] &&
+        $relationSettings['newFormAfterExistingRelations'] &&
         isset($this[$relationName]) && isset($this['new_'.$relationName])
       )
       {
@@ -101,8 +133,10 @@
   }
 
   /**
-   * Here we just drop the embedded creation forms if no value has been 
provided for them (this simulates a non-required embedded form),
-   * please provide the fields for the related embedded form in the call to 
$this->embedRelations() so we don't throw validation errors
+   * Here we just drop the embedded creation forms if no value has been
+   * provided for them (this simulates a non-required embedded form),
+   * please provide the fields for the related embedded form in the call
+   * to $this->embedRelations() so we don't throw validation errors
    * if the user did not want to add a new related object
    *
    * @see sfForm::doBind()
@@ -111,11 +145,13 @@
   {
     foreach ($this->embedRelations as $relationName => $keys)
     {
-      if (!isset($keys['noNewForm']) || !$keys['noNewForm'])
+      $keys = $this->addDefaultRelationSettings($keys);
+
+      if (!$keys['noNewForm'])
       {
         $containerName = 'new_'.$relationName;
 
-        if (!empty($keys['multipleNewForms'])) // just a single new form for 
this relation
+        if ($keys['multipleNewForms']) // just a single new form for this 
relation
         {
           if (array_key_exists($containerName, $values))
           {
@@ -295,7 +331,7 @@
    */
   protected function isNewFormEmpty(array $values, array $keys)
   {
-    if (!isset($keys['considerNewFormEmptyFields']) || 
count($keys['considerNewFormEmptyFields']) == 0 || !isset($values)) return 
false;
+    if (count($keys['considerNewFormEmptyFields']) == 0 || !isset($values)) 
return false;
 
     $emptyFields = 0;
     foreach ($keys['considerNewFormEmptyFields'] as $key)
@@ -314,7 +350,7 @@
     {
       return true;
     }
-    
+
     return false;
   }
 
@@ -330,8 +366,8 @@
   private function embeddedFormFactory($relationName, array $relationSettings, 
Doctrine_Relation $relation, $formLabel = null)
   {
       $newFormObject = $this->embeddedFormObjectFactory($relationName, 
$relation);
-      $formClass = !isset($relationSettings['newFormClass']) ? 
$relation->getClass().'Form' : $relationSettings['newFormClass'];
-      $formArgs = !isset($relationSettings['newFormClassArgs']) ? array() : 
$relationSettings['newFormClassArgs'];
+      $formClass = empty($relationSettings['newFormClass']) ? 
$relation->getClass().'Form' : $relationSettings['newFormClass'];
+      $formArgs = empty($relationSettings['newFormClassArgs']) ? array() : 
$relationSettings['newFormClassArgs'];
       $r = new ReflectionClass($formClass);
 
       $newForm = $r->newInstanceArgs(array_merge(array($newFormObject), 
array($formArgs)));
@@ -352,7 +388,7 @@
       {
         $newForm->getWidgetSchema()->setLabel($formLabel);
       }
-      
+
       return $newForm;
   }
 
@@ -373,7 +409,34 @@
     {
       $newFormObject = $this->getObject()->$relationName;
     }
-    
+
     return $newFormObject;
   }
+
+  /**
+   * Create and initialize form that will embed 'newly created relation' 
subforms
+   * If no object is given in 'newFormsContainerForm' parameter, it will
+   * initialize custom form bundled with this plugin
+   * @param array $relationSettings
+   * @return sfForm (ahNewRelationsContainerForm by default)
+   */
+  private function newFormsContainerFormFactory(array $relationSettings, 
$containerName)
+  {
+    $subForm = $relationSettings['newFormsContainerForm'];
+
+    if (!$subForm)
+    {
+      $subForm = new ahNewRelationsContainerForm(
+        array('new_relation' => $relationSettings['newRelationButtonLabel']),
+        array(
+          'containerName' => $containerName, 
+          'addByCloning' => $relationSettings['newRelationAddByCloning'],
+          'useJSFramework' => $relationSettings['newRelationUseJSFramework']
+        )
+      );
+    }
+
+    unset($subForm[$subForm->getCSRFFieldName()]);
+    return $subForm;
+  }
 }

Added: 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationField.php
===================================================================
--- 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationField.php
                         (rev 0)
+++ 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationField.php
 2010-04-29 08:07:41 UTC (rev 29311)
@@ -0,0 +1,28 @@
+<?php
+
+/**
+ * This class displays the button to add new embedded relation forms; it 
relies on client-side JavaScript to work.
+ * @author     Krzysztof Kotowicz <kkotowicz at gmail dot com>
+ */
+class ahNewRelationField extends sfWidgetForm
+{
+
+  protected function configure($options = array(), $attributes = array())
+  {
+    $this->addRequiredOption('containerName');
+    $this->addOption('addJavascript', false);
+    $this->addOption('useJSFramework', 'jQuery');
+  }
+
+  public function render($name, $value = null, $attributes = array(), $errors 
= array())
+  {
+    return $this->renderContentTag('button', $value !== null ? $value : '+', 
array('type' => 'button', 'class' => 'ahAddRelation', 'rel' => 
$this->getOption('containerName')));
+  }
+
+  public function getJavaScripts()
+  {
+    if (false === $this->getOption('addJavascript')) return array();
+    
+    return 
array(sprintf('/ahDoctrineEasyEmbeddedRelationsPlugin/js/ahDoctrineEasyEmbeddedRelationsPlugin.%s.js',
 $this->getOption('addJavascript')));
+  }
+}
\ No newline at end of file

Added: 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationsContainerForm.php
===================================================================
--- 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationsContainerForm.php
                                (rev 0)
+++ 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/lib/form/ahNewRelationsContainerForm.php
        2010-04-29 08:07:41 UTC (rev 29311)
@@ -0,0 +1,35 @@
+<?php
+
+/**
+ * Class used to embed new object forms in parent form
+ *
+ * @package    ahDoctrineEasyEmbeddedRelationsPlugin
+ * @subpackage form
+ * @author     Krzysztof Kotowicz <kkotowicz at gmail dot com>
+ */
+class ahNewRelationsContainerForm extends BaseForm
+{
+  public function configure()
+  {
+    $button = new ahNewRelationField(array(
+      'containerName' => $this->getOption('containerName'), 
+      'addJavascript' => $this->getOption('addByCloning'),
+      'useJSFramework' => $this->getOption('useJSFramework')
+    ));
+
+    $this->setWidget('_', $button);
+  }
+  
+  /**
+   * Moves button below embedded forms
+   * @inheritdoc
+   * @param string $name
+   * @param sfForm $form
+   * @param string $decorator
+   */
+  public function embedForm($name, sfForm $form, $decorator = null)
+  {
+    parent::embedForm($name, $form, $decorator);
+    $this->widgetSchema->moveField('_', sfWidgetFormSchema::LAST);
+  }
+}
\ No newline at end of file

Added: 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/js/ahDoctrineEasyEmbeddedRelationsPlugin.jQuery.js
===================================================================
--- 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/js/ahDoctrineEasyEmbeddedRelationsPlugin.jQuery.js
                          (rev 0)
+++ 
plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk/web/js/ahDoctrineEasyEmbeddedRelationsPlugin.jQuery.js
  2010-04-29 08:07:41 UTC (rev 29311)
@@ -0,0 +1,66 @@
+/**
+ * Code needed to clone nested relations forms
+ * @plugin ahDoctrineEasyEmbeddedRelationsPlugin
+ * @author Krzysztof Kotowicz <kkotowicz at gmail dot com>
+ */
+(function($) {
+
+       /**
+        * Increments field IDs and names by one
+        */
+       $.fn.incrementFields = function(container) {
+               return this.each(function() {
+                       var nameRe = new RegExp('\\[' + container + 
'\\]\\[(\\d+)\\]');
+                       var idRe = new RegExp('_' + container + '_(\\d+)_');
+
+                       $(this).find(':input').each(function() { // find each 
input
+                               var matches;
+                               if (matches = nameRe.exec(this.name)) { // 
check if its name contains [container][number]
+                                       // if so, increase the number in field 
name
+                                       this.name = 
this.name.replace(nameRe,'[' + container + '][' + (parseInt(matches[1],10)+1) + 
']');
+                                       if (this.id) { // and id
+                                               this.id = 
this.id.replace('_'+container+'_'+matches[1]+'_',
+                                                                               
                  '_'+container+'_'+(parseInt(matches[1],10)+1)+'_');
+                                       }
+                               }
+                               $(this).trigger('change.ah'); // trigger 
onchange event just for a case
+                       }).end();
+
+                       // fix labels
+                       $(this).find('label:for').each(function() {
+                               var matches;
+                               if (matches = idRe.exec($(this).attr('for'))) { 
// check if its name contains _container_number_
+                                       // if so, increase the number in label 
for attribute
+                                       $(this).attr('for', 
$(this).attr('for').replace(idRe,'_' + container + '_' + 
(parseInt(matches[1],10)+1) + '_'));
+                               }
+                       });
+
+                       // increase the number in first <th>
+                       $header = $(this).find('th').eq(0);
+                       if ($header.text().match(/^\d+$/)) {
+                               $header.text(parseInt($header.text(),10) + 1);
+                       }
+                       $(this).end();
+               });
+       }
+
+})(jQuery);
+
+jQuery(function($) {
+
+       // when clicking the 'add relation' button
+       $('.ahAddRelation').click(function() {
+
+               // find last row of my siblings (each row represents a subform)
+               $row = $(this).parents('tr').siblings(':last');
+
+               // clone it, increment the fields and insert it below, 
additionally triggering events
+               $row.clone()
+                       .incrementFields($(this).attr('rel'))
+                       
.trigger('beforeadd.ah').insertAfter($row).trigger('afteradd.ah');
+
+               //use events to further modify the cloned row like this
+               // $(document).bind('beforeadd.ah', function(event) { 
$(event.target).hide() /* event.target is cloned row */ });
+               // $(document).bind('afteradd.ah', function(event) { });
+       })
+});
\ No newline at end of file

-- 
You received this message because you are subscribed to the Google Groups 
"symfony SVN" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/symfony-svn?hl=en.

Reply via email to