![]() |
|
ahDoctrineEasyEmbeddedRelationsPlugin - 1.4.2Easily embed related forms and add new as well as edit and delete existing related records within one form. |
|
![]() |
70
users
Sign-in
to change your status |
Easily embed related forms and add new as well as edit and delete existing related records within one form. |
Easily embed related forms and add new as well as edit and delete existing related records within one form.
| Name | Status | |
|---|---|---|
|
|
lead | ed.ngisedpasa <<ta>> ofni |
|
|
lead | moc.liamg <<ta>> zciwotokk |
|
|
developer | moc.byrbaf <<ta>> byrbaf |
|
|
developer | gro.sredoc-xunil <<ta>> ylfdag |
Copyright (c) 2009-2010 asaphosting (Daniel Lohse & Steve Guhr)
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
| Version | License | API | Released |
|---|---|---|---|
| 1.4.4stable | MIT license | 1.1.0stable | 01/07/2010 |
| 1.4.3stable | MIT license | 1.1.0stable | 29/06/2010 |
| 1.4.2stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.4.1stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.4.0stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.3.4stable | MIT license | 1.3.0stable | 05/05/2010 |
| 1.3.1stable | MIT license | 1.0.0stable | 28/04/2010 |
| 1.3.0stable | MIT license | 1.0.0stable | 27/04/2010 |
| 1.2.4stable | MIT license | 1.0.0stable | 31/03/2010 |
| 1.2.2stable | MIT license | 1.0.0stable | 30/03/2010 |
| 1.2.0stable | MIT license | 1.0.0stable | 16/02/2010 |
| 1.1.0stable | MIT license | 1.0.0stable | 11/02/2010 |
| 1.0.1stable | MIT license | 1.0.0stable | 11/02/2010 |
| 1.0.0stable | MIT license | 1.0.0stable | 10/02/2010 |
| Version | License | API | Released |
|---|---|---|---|
| 1.4.4stable | MIT license | 1.1.0stable | 01/07/2010 |
| 1.4.3stable | MIT license | 1.1.0stable | 29/06/2010 |
| 1.4.2stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.4.1stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.4.0stable | MIT license | 1.1.0stable | 28/06/2010 |
| 1.3.4stable | MIT license | 1.3.0stable | 05/05/2010 |
| 1.3.1stable | MIT license | 1.0.0stable | 28/04/2010 |
| 1.3.0stable | MIT license | 1.0.0stable | 27/04/2010 |
| 1.2.4stable | MIT license | 1.0.0stable | 31/03/2010 |
| 1.2.2stable | MIT license | 1.0.0stable | 30/03/2010 |
| 1.2.0stable | MIT license | 1.0.0stable | 16/02/2010 |
| 1.1.0stable | MIT license | 1.0.0stable | 11/02/2010 |
| 1.0.1stable | MIT license | 1.0.0stable | 11/02/2010 |
| 1.0.0stable | MIT license | 1.0.0stable | 10/02/2010 |
bugfix: fixed is_a() producing E_STRICT warning in PHP between 5.0.0 and 5.3.0 because is_a() is deprecated in these versions - it's not beginning with 5.3.0 - d'oh! :)
bugfix: creating a completely new main object and, at the same time, also adding new related objects did not work
added new maintainers for the package (thanks koto!)
bugfix: fixed a bug regarding Doctrine inheritance (thanks Yves!)
bugfix: to disable the checkbox to delete existing related records set the option formClassArgs to this: 'formClassArgs' => array(array('ah_add_delete_checkbox' => false))
added new developer: FabryB :)
bugfix: newFormClassArgs option didn't work the way it was described in the README (option was automatically wrapped in an array) => please read the UPGRADE GUIDE that is packaged with this plugin! :)
bugfix: when using the multipleNewForms and newFormsInitialCount options it was indeed creating multiple forms to add related objects but it also did that for ONE-to-ONE relations ;-)
bugfix: newRelationButtonLabel did not work at all :(
new feature: customEmbeddedFormLabelMethod option is a method that is called on each existing related object (not the containing form!) so you can customize the form label that is shown in front of each existing embedded form. This option is new since version 1.4.0.
bugfix: The plugin finally works with embedded forms that have checkboxes, radio buttons and/or file upload fields (what's especially interesting is the use of sfWidgetFormInputFileEditable)!
I also finally added unit tests that should cover at least 80% of the functionality. Because I don't have that much time I used the symfony Core's unit tests as a starting point so they actually live inside the lib/vendor/symfony directory of one of my projects. If there's someone who knows how to set up plugin-internal unit tests (with a SQlite database for testing persistence stuff), I'd be glad to provide these unit tests. :) Help's always welcome!
Yikes! I forgot to add the new files that were introduced in version 1.3 and up. I was also naive enough to think PEAR would automatically include those. :(
Bugfix: Embedded i18n forms could not be saved; thanks for the bug info to Sári Márton! Trivial: removed some debug logger calls (they were commented out anyway)
Thanks to koto (on GitHub) the whole workhorse class has been refactored into more manageable parts! :)
in addition to this koto has been kind enough to add the ability to add multiple new objects in one go, which he also documented in the README
add to that the ability to add new forms dynamically with JavaScript (think of rendering a partial with the "Add form" inside via AJAX) and you'll know that this rightfully deserved a minor version number increase!
Thank you koto!
added ability to display the empty form to add new related objects below the already existing related objects
documented new option in the README Because of an error, there was no "real" release version 1.2.3, there is a tag for it in the Subversion repository but nothing more. :)
cleaned up TODO
no code changes! Because of an error, there was no "real" release version 1.2.1, there is a tag for it in the Subversion repository but nothing more. :)
fixed: no useless "add new" forms anymore when the embedded relation is one-to-one and a related object exists :)
removed all debug code calls
improved code documentation
fixed a few bugs, so passing options to the embedded forms actually works.
not necessary anymore to create a dedicated form to add the delete checkboxes, this is now handled by symfony's event dispatcher and the form.post_configure event. :)
updated the README
Fixed README (typos, logic).
Initial release.
The ahDoctrineEasyEmbeddedRelationsPlugin is a symfony plugin that provides a Doctrine base form class to allow easy and more powerful embedding of forms.
For the inspiration of this plugin please read this blog post: Embedding Relations in Forms with Symfony 1.3 and Doctrine. Thanks, Nicolas! :)
Install the plugin (via a package)
symfony plugin:install ahDoctrineEasyEmbeddedRelationsPlugin
Install the plugin (via a Subversion checkout)
svn co http://svn.symfony-project.com/plugins/ahDoctrineEasyEmbeddedRelationsPlugin/trunk
plugins/ahDoctrineEasyEmbeddedRelationsPlugin
Install the plugin (via a Git clone)
git clone git://github.com/annismckenzie/ahDoctrineEasyEmbeddedRelationsPlugin.git
Activate the plugin in config/ProjectConfiguration.class.php
class ProjectConfiguration extends sfProjectConfiguration { public function setup() { $this->enablePlugins(array( 'sfDoctrinePlugin', 'ahDoctrineEasyEmbeddedRelationsPlugin', '...' )); } }
Change the parent class in lib/form/doctrine/BaseFormDoctrine.class.php to ahBaseFormDoctrine
abstract class BaseFormDoctrine extends ahBaseFormDoctrine { ... }
Publish the plugin assets
symfony plugin:publish-assets
Clear your cache
symfony cc
Here is an example schema definition:
ahIntranetSubversionRepository:
actAs:
Timestampable: ~
tableName: ah_intranet_subversion_repository
columns:
id: { type: integer(4), primary: true, autoincrement: true }
project_id: { type: integer(4), notnull: true }
name: { type: string(64), notnull: true }
repo_path: { type: string(255), notnull: true }
repo_username: { type: string(64), notnull: true }
repo_password: { type: string(128), notnull: true }
relations:
ahProjectmanagerProject: { local: project_id, foreign: id, type: one, onDelete: CASCADE, foreignAlias: Repositories }
To embed one or more relations, add this to one of your form's configure method (or in a plugin form class: to the setup method):
public function configure() { ... $this->embedRelations(array( 'Repositories' => array( 'considerNewFormEmptyFields' => array('name', 'repo_path', 'repo_username', 'repo_password'), 'noNewForm' => true, 'newFormLabel' => 'New repository!!!', 'newFormClass' => 'ahIntranetSubversionRepositoryNewForm', 'newFormClassArgs' => array(array('sf_user' => $this->getOption('sf_user'))), 'displayEmptyRelations' => false, 'formClass' => 'ahIntranetSubversionRepositoryEmbeddedForm', 'formClassArgs' => array(array('ah_add_delete_checkbox' => false, 'another_form_option' => ...)), 'newFormAfterExistingRelations' => false, 'formFormatter' => null, 'multipleNewForms' => true, 'newFormsInitialCount' => 2, 'newFormsContainerForm' => null, // pass BaseForm object here or we will create ahNewRelationsContainerForm 'newRelationButtonLabel' => '+', 'newRelationAddByCloning' => true, 'newRelationUseJSFramework' => 'jQuery', 'customEmbeddedFormLabelMethod' => 'getLabelTitle' ), '...' => array( ... ) )); }
Be careful if you're using the new useFields method as this would unset the embedded forms again!
Also, please be aware that the embedRelations method does not follow the embedRelation method in that you cannot define an alias to use for the relation, you need to specify the relation key you used in the schema, which is, in this case, Repositories!
Each array defines one embedded relation and you can define a handful of options.
The minimal code is this:
public function configure() { ... $this->embedRelations(array( 'Repositories' => array( 'considerNewFormEmptyFields' => array('name', 'repo_path', 'repo_username', 'repo_password') ) )); }
Only the first option is required, the rest can either be guessed using the schema and Doctrine or is an option for which we provide sensible defaults. :)
considerNewFormEmptyFields (the only required option, array): trouble starts when the user does not want to add a new related object but only wants to edit the main object's properties.
As the embedded forms are validated, an error is thrown if one of the embedded form's field's is required.
To remedy that you'll have to add all the fields to this array and if all of these are empty, the empty form is dropped and no empty object is saved to the database (or validation errors thrown).
noNewForm (boolean, not required): if false, no empty form to add a new related object is embedded so you can only manage existing related objects.
newFormLabel (string, not required): the label that is shown for the new embedded form. If the form is used in the admin generator, label definitions in the generator.yml take precedence over this option:
generator:
...
param:
...
config:
actions: ~
fields:
...
new_Repositories:
label: New repository
list:
...
The key to use in the fields array above is 'new_relationName' ('new_Repositories' in this case, see the example above).
newFormClass (string, not required): the form class to use for the empty form
newFormClassArgs (array of arrays, not required): form class options to pass to the empty form class on instantiation.
Explanation for why it's an array of arrays: the way embedRelation works uses reflection to construct the right form objects. Now, the first argument is always the model object, the second is the form option array and the third is the local CSRF secret for the form.
You don't need to worry about the first one (the model object) because this is always null for the new form. If you want to pass some more options to the related form object (like the user object to avoid using sfContext) just follow the example above.
I could have changed this (because I implemented it) but I don't want to confuse the developer because when you look at the option formClassArgs below it's the same mechanism and I can't change that short of copying the whole embedRelation method over to the ahBaseFormDoctrine class, thereby losing the chance to automatically get upstream bugfixes. :)
formClass (string, not required): the form class to use for the existing related objects.
formClassArgs (array of arrays, not required): form class options to pass to the existing related objects form class on instantiation.
As of version 1.1 it's not necessary to create a separate form class for the existing related forms to display the delete checkbox.
This is now handled by the symfony event dispatcher. If you want to change how that works you can always copy over this method and change it to suit your needs:
public function listenToFormPostConfigureEvent(sfEvent $event) { $form = $event->getSubject(); if($form instanceof sfFormDoctrine && $form->getOption('ah_add_delete_checkbox', false) && !$form->isNew()) { $form->setWidget('delete_object', new sfWidgetFormInputCheckbox(array('label' => 'Just destroy the damn object!'))); $form->setValidator('delete_object', new sfValidatorPass()); } }
Or if you're like me and want to save space, here's another version you can use:
public function listenToFormPostConfigureEvent(sfEvent $event) { if ($form = parent::listenToFormPostConfigureEvent($event)) { $form->widgetSchema['delete_object']->setOption('label', 'Just destroy the damn object!'); } }
This works because we're calling the plugin's event handler method. This either returns the form so it added the delete checkbox and the validator and you can act on that, or it returns false and you don't act on that. Neat and tidy. :)
If you want to disable the checkbox to delete existing related records entirely set this option to this: 'formClassArgs' => array(array('ah_add_delete_checkbox' => false)) or add it accordingly to your already existing form class arguments.
displayEmptyRelations (boolean, not required): set this option to true (false is the default) if you want to check for existing related objects yourself. This can be done in the form template and is useful if you want to let the user know that 'There are no related repositories yet.'. The default is just not displaying anything in this case, which works for me. :)
newFormAfterExistingRelations (boolean, not required): set this option to true to display the empty form to add new related objects below the existing related objects
formFormatter (string, not required): class name of form formatter for all forms embedding the relation forms
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.)
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 a jQuery and a MooTools version available. Pass 'jQuery' or 'MooTools' as the value for the option.
customEmbeddedFormLabelMethod (string, not required): This method is called on each existing related object (not the containing form!) so you can customize the form label that is shown in front of each existing embedded form. This option is new since version 1.4.0.
I can be reached via e-mail: info@asapdesign.de
If you find bugs, have questions and/or feature requests, you can post to the symfony-user mailing list, of which I am an avid follower. :)
