From: Gustavo Martin Morcuende Date: Thu, 17 May 2012 01:57:43 +0000 (+0200) Subject: Create associations between offices and ads X-Git-Url: https://git.gumartinm.name/?a=commitdiff_plain;h=5f03f9b1f8bc4eb912bfdcd83b44fa2d3fe1c9d1;p=mobi%2F.git Create associations between offices and ads Using double list and the plguin sfFormExtraPlugin --- diff --git a/apps/companyfront/modules/office/actions/actions.class.php b/apps/companyfront/modules/office/actions/actions.class.php index f134f0e..14c3305 100644 --- a/apps/companyfront/modules/office/actions/actions.class.php +++ b/apps/companyfront/modules/office/actions/actions.class.php @@ -136,4 +136,26 @@ class officeActions extends sfActions $this->redirect('office/edit?id='.$office->getId()); } } + + public function executeLink(sfWebRequest $request) + { + $this->forward404Unless($office = Doctrine_Core::getTable('Office')->find(array($request->getParameter('id'))), sprintf('Object office does not exist (%s).', $request->getParameter('id'))); + + //Get user Id + $userId = $this->getUser()->getGuardUser()->getId(); + + //Get company owned by that user and insert value in form + $companyUserId = CompanyTable::getInstance()->findOneByUserId($userId)->getId(); + + //Get id number sent by the user (never trust the users) + $officeId = $request->getParameter('id'); + + $companyOfficeId = $office->getCompanyId(); + + $this->forward404Unless($companyOfficeId == $companyUserId, sprintf('Office does not exist (%s).', $request->getParameter('id'))); + + $officeAds = OfficeAdsTable::getInstance()->findOneByOfficeId($officeId); + + $this->form = new OfficeAdsForm($officeAds, array('companyId' => $companyOfficeId)); + } } diff --git a/apps/companyfront/modules/office/templates/_formCustomOfficeAds.php b/apps/companyfront/modules/office/templates/_formCustomOfficeAds.php new file mode 100644 index 0000000..74bb006 --- /dev/null +++ b/apps/companyfront/modules/office/templates/_formCustomOfficeAds.php @@ -0,0 +1,23 @@ + + + + +
isMultipart() and print 'enctype="multipart/form-data" ' ?>> +getObject()->isNew()): ?> + + + + + + + + + + + +
+ renderHiddenFields(false) ?> +   + /> +
+
diff --git a/apps/companyfront/modules/office/templates/_list.php b/apps/companyfront/modules/office/templates/_list.php index 67c935d..12cfef5 100644 --- a/apps/companyfront/modules/office/templates/_list.php +++ b/apps/companyfront/modules/office/templates/_list.php @@ -22,7 +22,7 @@ getLongitude() ?> getLatitude() ?> - + ', 'office/delete?id='.$office->getId(), array('method' => 'delete', 'confirm' => 'Are you sure?')) ?> diff --git a/apps/companyfront/modules/office/templates/linkSuccess.php b/apps/companyfront/modules/office/templates/linkSuccess.php new file mode 100644 index 0000000..f4174d5 --- /dev/null +++ b/apps/companyfront/modules/office/templates/linkSuccess.php @@ -0,0 +1,3 @@ +

+ + $form)) ?> diff --git a/config/ProjectConfiguration.class.php b/config/ProjectConfiguration.class.php index 1015543..a302bcb 100644 --- a/config/ProjectConfiguration.class.php +++ b/config/ProjectConfiguration.class.php @@ -9,5 +9,6 @@ class ProjectConfiguration extends sfProjectConfiguration { $this->enablePlugins('sfDoctrinePlugin'); $this->enablePlugins('sfDoctrineGuardPlugin'); + $this->enablePlugins('sfFormExtraPlugin'); } } diff --git a/lib/form/doctrine/OfficeAdsForm.class.php b/lib/form/doctrine/OfficeAdsForm.class.php index f6ea014..f1689bd 100644 --- a/lib/form/doctrine/OfficeAdsForm.class.php +++ b/lib/form/doctrine/OfficeAdsForm.class.php @@ -5,12 +5,50 @@ * * @package mobiads * @subpackage form - * @author Your name here - * @version SVN: $Id: sfDoctrineFormTemplate.php 23810 2009-11-12 11:07:44Z Kris.Wallsmith $ + * @author Gustavo Martin Morcuende + * @version */ class OfficeAdsForm extends BaseOfficeAdsForm { public function configure() { + //Narrow down options. + //We must just show those ads owned by the office's company. + $query = AdTable::getInstance()->getAdsByCompanyIdQuery($this->getOption('companyId')); + + $this->useFields(array('ad_id')); + + $this->widgetSchema['ad_id'] = new sfWidgetFormDoctrineChoice(array('model' => $this->getRelatedModelName('Ad'), + 'add_empty' => false, + 'multiple' => true, + 'expanded' => false, + 'renderer_class' => 'sfWidgetFormSelectDoubleList', + 'query' => $query)); + + $this->validatorSchema['ad_id'] = new sfValidatorDoctrineChoice(array('model' => $this->getRelatedModelName('Ad'), + 'multiple' => true, + 'query' => $query)); + } + + /** + * Overriding updateDefaultsFromObject method in order to preselect fields. + * + * The already chosen ads must be shown as selected. + * see: lib/vendor/symfony/lib/plugins/sfDoctrinePlugin/lib/form/sfFormDoctrine.class.php + */ + protected function updateDefaultsFromObject() + { + parent::updateDefaultsFromObject(); + + //We just preselect fields when the Doctrine Record Object comes from the data base. + if (!$this->getObject()->isNew()) + { + $officeAds = OfficeAdsTable::getInstance()->findByOfficeId($this->getObject()->getOfficeId()); + foreach ($officeAds as $officeAd) + { + $already_chosen[] = $officeAd->getAdId(); + } + $this->setDefault('ad_id', $already_chosen); + } } } diff --git a/lib/model/doctrine/AdTable.class.php b/lib/model/doctrine/AdTable.class.php index d721969..1a7b840 100644 --- a/lib/model/doctrine/AdTable.class.php +++ b/lib/model/doctrine/AdTable.class.php @@ -16,4 +16,15 @@ class AdTable extends Doctrine_Table { return Doctrine_Core::getTable('Ad'); } -} \ No newline at end of file + + + /** + * Returns ads by company id. + * + * @return related ads to a company id as Doctrine Query + */ + public function getAdsByCompanyIdQuery($companyId) + { + return $this->createQuery('ad')->where('ad.company_id = ?', $companyId); + } +} diff --git a/lib/model/doctrine/OfficeAdsTable.class.php b/lib/model/doctrine/OfficeAdsTable.class.php index 4caab69..cb12534 100644 --- a/lib/model/doctrine/OfficeAdsTable.class.php +++ b/lib/model/doctrine/OfficeAdsTable.class.php @@ -16,4 +16,4 @@ class OfficeAdsTable extends Doctrine_Table { return Doctrine_Core::getTable('OfficeAds'); } -} \ No newline at end of file +} diff --git a/plugins/.filemap b/plugins/.filemap index 074fe08..49d70a6 100644 --- a/plugins/.filemap +++ b/plugins/.filemap @@ -1 +1 @@ -a:1:{s:4:"data";a:86:{s:48:"sfdoctrineguardplugin/config/doctrine/schema.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/config/sfDoctrineGuardPluginConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:55:"sfdoctrineguardplugin/data/fixtures/fixtures.yml.sample";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:36:"sfdoctrineguardplugin/data/tasks/.sf";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:42:"sfdoctrineguardplugin/i18n/sf_guard.es.xml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:42:"sfdoctrineguardplugin/i18n/sf_guard.fr.xml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:80:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardGroupFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:85:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardPermissionFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardUserFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:82:"sfdoctrineguardplugin/lib/form/base/BasesfGuardRequestForgotPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:88:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardChangeUserPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:76:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardFormSignin.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardRegisterForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardUserAdminForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:72:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardGroupForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:77:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardPermissionForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:71:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardUserForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardChangeUserPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardFormSignin.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardRegisterForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:70:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardUserAdminForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/form/sfGuardRequestForgotPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardForgotPassword.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:83:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardForgotPasswordTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroup.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:84:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:75:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardRememberKey.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:80:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardRememberKeyTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserGroup.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserGroupTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:83:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:58:"sfdoctrineguardplugin/lib/routing/sfGuardRouting.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:60:"sfdoctrineguardplugin/lib/task/sfGuardAddGroupTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:65:"sfdoctrineguardplugin/lib/task/sfGuardAddPermissionTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:66:"sfdoctrineguardplugin/lib/task/sfGuardChangePasswordTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/lib/task/sfGuardCreateUserTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/task/sfGuardPromoteSuperAdminTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:60:"sfdoctrineguardplugin/lib/user/sfGuardSecurityUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:66:"sfdoctrineguardplugin/lib/validator/sfGuardValidatorUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/lib/sfGuardBasicSecurityFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:59:"sfdoctrineguardplugin/lib/sfGuardRememberMeFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/modules/sfGuardAuth/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:70:"sfdoctrineguardplugin/modules/sfGuardAuth/actions/components.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:61:"sfdoctrineguardplugin/modules/sfGuardAuth/config/security.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:81:"sfdoctrineguardplugin/modules/sfGuardAuth/lib/BasesfGuardAuthComponents.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/_signin_form.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/secureSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/signinSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:77:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:98:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/lib/BasesfGuardForgotPasswordActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/_new_password.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/_send_request.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/changeSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/indexSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardGroup/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:63:"sfdoctrineguardplugin/modules/sfGuardGroup/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:91:"sfdoctrineguardplugin/modules/sfGuardGroup/lib/sfGuardGroupGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:84:"sfdoctrineguardplugin/modules/sfGuardGroup/lib/sfGuardGroupGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/modules/sfGuardPermission/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardPermission/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:101:"sfdoctrineguardplugin/modules/sfGuardPermission/lib/sfGuardPermissionGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:94:"sfdoctrineguardplugin/modules/sfGuardPermission/lib/sfGuardPermissionGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:71:"sfdoctrineguardplugin/modules/sfGuardRegister/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/modules/sfGuardRegister/actions/components.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:86:"sfdoctrineguardplugin/modules/sfGuardRegister/lib/BasesfGuardRegisterActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:89:"sfdoctrineguardplugin/modules/sfGuardRegister/lib/BasesfGuardRegisterComponents.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:65:"sfdoctrineguardplugin/modules/sfGuardRegister/templates/_form.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:72:"sfdoctrineguardplugin/modules/sfGuardRegister/templates/indexSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/modules/sfGuardUser/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/modules/sfGuardUser/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:89:"sfdoctrineguardplugin/modules/sfGuardUser/lib/sfGuardUserGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:82:"sfdoctrineguardplugin/modules/sfGuardUser/lib/sfGuardUserGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:31:"sfdoctrineguardplugin/.DS_Store";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:29:"sfdoctrineguardplugin/LICENSE";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:28:"sfdoctrineguardplugin/README";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:53:"sfdoctrineguardplugin/sfDoctrineGuardPlugin-5.0.0.tgz";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:29:"sfdoctrineguardplugin/VERSION";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}}} \ No newline at end of file +a:1:{s:4:"data";a:118:{s:48:"sfdoctrineguardplugin/config/doctrine/schema.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/config/sfDoctrineGuardPluginConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:55:"sfdoctrineguardplugin/data/fixtures/fixtures.yml.sample";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:36:"sfdoctrineguardplugin/data/tasks/.sf";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:42:"sfdoctrineguardplugin/i18n/sf_guard.es.xml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:42:"sfdoctrineguardplugin/i18n/sf_guard.fr.xml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:80:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardGroupFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:85:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardPermissionFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/filter/doctrine/PluginsfGuardUserFormFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:82:"sfdoctrineguardplugin/lib/form/base/BasesfGuardRequestForgotPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:88:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardChangeUserPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:76:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardFormSignin.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardRegisterForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/form/doctrine/base/BasesfGuardUserAdminForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:72:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardGroupForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:77:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardPermissionForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:71:"sfdoctrineguardplugin/lib/form/doctrine/PluginsfGuardUserForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardChangeUserPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardFormSignin.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardRegisterForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:70:"sfdoctrineguardplugin/lib/form/doctrine/sfGuardUserAdminForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/form/sfGuardRequestForgotPasswordForm.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardForgotPassword.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:83:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardForgotPasswordTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroup.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:84:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardGroupTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:75:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardRememberKey.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:80:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardRememberKeyTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserGroup.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserGroupTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserPermission.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:83:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserPermissionTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/lib/model/doctrine/PluginsfGuardUserTable.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:58:"sfdoctrineguardplugin/lib/routing/sfGuardRouting.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:60:"sfdoctrineguardplugin/lib/task/sfGuardAddGroupTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:65:"sfdoctrineguardplugin/lib/task/sfGuardAddPermissionTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:66:"sfdoctrineguardplugin/lib/task/sfGuardChangePasswordTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/lib/task/sfGuardCreateUserTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/lib/task/sfGuardPromoteSuperAdminTask.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:60:"sfdoctrineguardplugin/lib/user/sfGuardSecurityUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:66:"sfdoctrineguardplugin/lib/validator/sfGuardValidatorUser.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/lib/sfGuardBasicSecurityFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:59:"sfdoctrineguardplugin/lib/sfGuardRememberMeFilter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/modules/sfGuardAuth/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:70:"sfdoctrineguardplugin/modules/sfGuardAuth/actions/components.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:61:"sfdoctrineguardplugin/modules/sfGuardAuth/config/security.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardAuth/lib/BasesfGuardAuthActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:81:"sfdoctrineguardplugin/modules/sfGuardAuth/lib/BasesfGuardAuthComponents.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/_signin_form.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/secureSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:69:"sfdoctrineguardplugin/modules/sfGuardAuth/templates/signinSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:77:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:98:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/lib/BasesfGuardForgotPasswordActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/_new_password.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/_send_request.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:79:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/changeSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardForgotPassword/templates/indexSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardGroup/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:63:"sfdoctrineguardplugin/modules/sfGuardGroup/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:91:"sfdoctrineguardplugin/modules/sfGuardGroup/lib/sfGuardGroupGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:84:"sfdoctrineguardplugin/modules/sfGuardGroup/lib/sfGuardGroupGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:73:"sfdoctrineguardplugin/modules/sfGuardPermission/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:68:"sfdoctrineguardplugin/modules/sfGuardPermission/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:101:"sfdoctrineguardplugin/modules/sfGuardPermission/lib/sfGuardPermissionGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:94:"sfdoctrineguardplugin/modules/sfGuardPermission/lib/sfGuardPermissionGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:71:"sfdoctrineguardplugin/modules/sfGuardRegister/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:74:"sfdoctrineguardplugin/modules/sfGuardRegister/actions/components.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:86:"sfdoctrineguardplugin/modules/sfGuardRegister/lib/BasesfGuardRegisterActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:89:"sfdoctrineguardplugin/modules/sfGuardRegister/lib/BasesfGuardRegisterComponents.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:65:"sfdoctrineguardplugin/modules/sfGuardRegister/templates/_form.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:72:"sfdoctrineguardplugin/modules/sfGuardRegister/templates/indexSuccess.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:67:"sfdoctrineguardplugin/modules/sfGuardUser/actions/actions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:62:"sfdoctrineguardplugin/modules/sfGuardUser/config/generator.yml";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:78:"sfdoctrineguardplugin/modules/sfGuardUser/lib/BasesfGuardUserActions.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:89:"sfdoctrineguardplugin/modules/sfGuardUser/lib/sfGuardUserGeneratorConfiguration.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:82:"sfdoctrineguardplugin/modules/sfGuardUser/lib/sfGuardUserGeneratorHelper.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:31:"sfdoctrineguardplugin/.DS_Store";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:29:"sfdoctrineguardplugin/LICENSE";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:28:"sfdoctrineguardplugin/README";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:53:"sfdoctrineguardplugin/sfDoctrineGuardPlugin-5.0.0.tgz";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:29:"sfdoctrineguardplugin/VERSION";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:21:"sfdoctrineguardplugin";}s:31:"sfformextraplugin/bin/prove.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:51:"sfformextraplugin/lib/form/sfFormLanguage.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:84:"sfformextraplugin/lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:62:"sfformextraplugin/lib/validator/sfValidatorBlacklist.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:62:"sfformextraplugin/lib/validator/sfValidatorReCaptcha.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:71:"sfformextraplugin/lib/validator/sfValidatorSchemaTimeInterval.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:60:"sfformextraplugin/lib/validator/sfValidatorDefault.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:72:"sfformextraplugin/lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:78:"sfformextraplugin/lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:70:"sfformextraplugin/lib/widget/sfWidgetFormJQueryAutocompleter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:61:"sfformextraplugin/lib/widget/sfWidgetFormJQueryDate.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:70:"sfformextraplugin/lib/widget/sfWidgetFormPropelChoiceGrouped.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:76:"sfformextraplugin/lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:60:"sfformextraplugin/lib/widget/sfWidgetFormReCaptcha.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:67:"sfformextraplugin/lib/widget/sfWidgetFormSelectDoubleList.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:64:"sfformextraplugin/lib/widget/sfWidgetFormSelectUSState.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:66:"sfformextraplugin/lib/widget/sfWidgetFormTextareaTinyMCE.class.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:50:"sfformextraplugin/test/form/sfFormLanguageTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:61:"sfformextraplugin/test/validator/sfValidatorReCaptchaTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:61:"sfformextraplugin/test/validator/sfValidatorBlacklistTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:70:"sfformextraplugin/test/validator/sfValidatorSchemaTimeIntervalTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:59:"sfformextraplugin/test/validator/sfValidatorDefaultTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:59:"sfformextraplugin/test/widget/sfWidgetFormReCaptchaTest.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:36:"sfformextraplugin/test/bootstrap.php";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:50:"sfformextraplugin/web/css/jquery.autocompleter.css";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:39:"sfformextraplugin/web/js/double_list.js";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:48:"sfformextraplugin/web/js/jquery.autocompleter.js";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:42:"sfformextraplugin/web/images/indicator.gif";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:37:"sfformextraplugin/web/images/next.png";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:41:"sfformextraplugin/web/images/previous.png";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:24:"sfformextraplugin/README";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}s:25:"sfformextraplugin/LICENSE";a:2:{i:0;s:27:"plugins.symfony-project.org";i:1;s:17:"sfformextraplugin";}}} \ No newline at end of file diff --git a/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg b/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg index 7feaa3d..5b236ff 100644 --- a/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg +++ b/plugins/.registry/.channel.pear.symfony-project.com/symfony.reg @@ -1,4 +1,4 @@ a:18:{s:4:"name";s:7:"symfony";s:7:"attribs";a:5:{s:7:"version";s:3:"2.0";s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:18:"xsi:schemaLocation";s:159:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 - http://pear.php.net/dtd/package-2.0.xsd";}s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:7:"symfony";s:11:"description";s:7:"symfony";s:4:"lead";a:4:{s:4:"name";s:16:"Fabien Potencier";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2012-05-10";s:7:"version";a:2:{s:7:"release";s:6:"1.4.18";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";s:11:"MIT License";s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:1:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}}}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.2.4";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.3";}}}s:10:"phprelease";a:0:{}s:8:"filelist";a:0:{}s:3:"old";a:7:{s:7:"version";s:6:"1.4.18";s:12:"release_date";s:10:"2012-05-10";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT License";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.2.4";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.3";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:16:"Fabien Potencier";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1336675411;} \ No newline at end of file + http://pear.php.net/dtd/package-2.0.xsd";}s:7:"channel";s:24:"pear.symfony-project.com";s:7:"summary";s:7:"symfony";s:11:"description";s:7:"symfony";s:4:"lead";a:4:{s:4:"name";s:16:"Fabien Potencier";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}s:4:"date";s:10:"2012-05-17";s:7:"version";a:2:{s:7:"release";s:6:"1.4.18";s:3:"api";s:5:"1.4.0";}s:9:"stability";a:2:{s:7:"release";s:4:"beta";s:3:"api";s:4:"beta";}s:7:"license";s:11:"MIT License";s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:1:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}}}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.2.4";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.3";}}}s:10:"phprelease";a:0:{}s:8:"filelist";a:0:{}s:3:"old";a:7:{s:7:"version";s:6:"1.4.18";s:12:"release_date";s:10:"2012-05-17";s:13:"release_state";s:4:"beta";s:15:"release_license";s:11:"MIT License";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.2.4";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.3";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:1:{i:0;a:5:{s:4:"name";s:16:"Fabien Potencier";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1337219150;} \ No newline at end of file diff --git a/plugins/.registry/.channel.plugins.symfony-project.org/sfformextraplugin.reg b/plugins/.registry/.channel.plugins.symfony-project.org/sfformextraplugin.reg new file mode 100644 index 0000000..33f08e5 --- /dev/null +++ b/plugins/.registry/.channel.plugins.symfony-project.org/sfformextraplugin.reg @@ -0,0 +1,12 @@ +a:23:{s:7:"attribs";a:6:{s:5:"xmlns";s:35:"http://pear.php.net/dtd/package-2.0";s:11:"xmlns:tasks";s:33:"http://pear.php.net/dtd/tasks-1.0";s:9:"xmlns:xsi";s:41:"http://www.w3.org/2001/XMLSchema-instance";s:15:"packagerversion";s:5:"1.9.1";s:7:"version";s:3:"2.0";s:18:"xsi:schemaLocation";s:147:"http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd";}s:4:"name";s:17:"sfFormExtraPlugin";s:7:"channel";s:27:"plugins.symfony-project.org";s:7:"summary";s:31:"Validators, Widgets, and Forms.";s:11:"description";s:31:"Validators, Widgets, and Forms.";s:4:"lead";a:4:{s:4:"name";s:16:"Fabien Potencier";s:4:"user";s:6:"fabpot";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";}s:9:"developer";a:3:{i:0;a:4:{s:4:"name";s:17:"Nicolas Perriault";s:4:"user";s:7:"nicolas";s:5:"email";s:37:"nicolas.perriault@symfony-project.com";s:6:"active";s:3:"yes";}i:1;a:4:{s:4:"name";s:14:"Kris Wallsmith";s:4:"user";s:14:"Kris.Wallsmith";s:5:"email";s:34:"kris.wallsmith@symfony-project.com";s:6:"active";s:3:"yes";}i:2;a:4:{s:4:"name";s:10:"Hugo Hamon";s:4:"user";s:10:"hugo.hamon";s:5:"email";s:21:"hugo.hamon@sensio.com";s:6:"active";s:3:"yes";}}s:4:"date";s:10:"2010-08-25";s:4:"time";s:8:"14:00:37";s:7:"version";a:2:{s:7:"release";s:5:"1.1.3";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}s:5:"notes";s:1:"-";s:8:"contents";a:1:{s:3:"dir";a:2:{s:7:"attribs";a:1:{s:4:"name";s:1:"/";}s:4:"file";a:32:{i:0;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"dd477c00b9182a8fce0a2931b2afe14f";s:4:"name";s:13:"bin/prove.php";s:4:"role";s:4:"data";}}i:1;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"352b4711bca96a9ef711c02ba51a7487";s:4:"name";s:33:"lib/form/sfFormLanguage.class.php";s:4:"role";s:4:"data";}}i:2;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1374000a0198f4a174f80795e60e7c71";s:4:"name";s:66:"lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php";s:4:"role";s:4:"data";}}i:3;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"47573deff2c7264ae1a31ead15940eed";s:4:"name";s:44:"lib/validator/sfValidatorBlacklist.class.php";s:4:"role";s:4:"data";}}i:4;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"71d741ed1a332e2c3c5e5eba43061123";s:4:"name";s:44:"lib/validator/sfValidatorReCaptcha.class.php";s:4:"role";s:4:"data";}}i:5;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"f1af2b598238238258888f18dbc8a257";s:4:"name";s:53:"lib/validator/sfValidatorSchemaTimeInterval.class.php";s:4:"role";s:4:"data";}}i:6;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"122f99df59284f63338fd9a1e055e4ff";s:4:"name";s:42:"lib/validator/sfValidatorDefault.class.php";s:4:"role";s:4:"data";}}i:7;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b0a625150802410c9a39dee434746908";s:4:"name";s:54:"lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php";s:4:"role";s:4:"data";}}i:8;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8d3f91f1b54429c94b71517bd3840e20";s:4:"name";s:60:"lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php";s:4:"role";s:4:"data";}}i:9;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8ca49e7b709485623ebd124950a0a41f";s:4:"name";s:52:"lib/widget/sfWidgetFormJQueryAutocompleter.class.php";s:4:"role";s:4:"data";}}i:10;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0a004f96c83c50872775bcc698d5dabb";s:4:"name";s:43:"lib/widget/sfWidgetFormJQueryDate.class.php";s:4:"role";s:4:"data";}}i:11;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"8c909201670d42f4d4ddfe46eab45adb";s:4:"name";s:52:"lib/widget/sfWidgetFormPropelChoiceGrouped.class.php";s:4:"role";s:4:"data";}}i:12;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"45adc6b7bfb2296d7bc77a83a441ac88";s:4:"name";s:58:"lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php";s:4:"role";s:4:"data";}}i:13;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9feb211dbd9e4e274b7981f41af339cb";s:4:"name";s:42:"lib/widget/sfWidgetFormReCaptcha.class.php";s:4:"role";s:4:"data";}}i:14;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"83860c7eea89ef17f0e4d88268fbb7fc";s:4:"name";s:49:"lib/widget/sfWidgetFormSelectDoubleList.class.php";s:4:"role";s:4:"data";}}i:15;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4b4bedb41a4adb487ecc39cc47be4eab";s:4:"name";s:46:"lib/widget/sfWidgetFormSelectUSState.class.php";s:4:"role";s:4:"data";}}i:16;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b4e4b61fba61b26db3ac30bb5933771b";s:4:"name";s:48:"lib/widget/sfWidgetFormTextareaTinyMCE.class.php";s:4:"role";s:4:"data";}}i:17;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"ceecaca65fdf3b4c5e037ab6e696d06a";s:4:"name";s:32:"test/form/sfFormLanguageTest.php";s:4:"role";s:4:"data";}}i:18;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"6ea19158046962f6ad76776ed3ad8673";s:4:"name";s:43:"test/validator/sfValidatorReCaptchaTest.php";s:4:"role";s:4:"data";}}i:19;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"0c08b48fbc88fb98aa6062809cba54c8";s:4:"name";s:43:"test/validator/sfValidatorBlacklistTest.php";s:4:"role";s:4:"data";}}i:20;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"1f6fd7556f6f3a68b7a31ba859c4175b";s:4:"name";s:52:"test/validator/sfValidatorSchemaTimeIntervalTest.php";s:4:"role";s:4:"data";}}i:21;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"92b4a5838358108197afe3afe8aee679";s:4:"name";s:41:"test/validator/sfValidatorDefaultTest.php";s:4:"role";s:4:"data";}}i:22;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"993dc134aefab7538455472af3a3c5a4";s:4:"name";s:41:"test/widget/sfWidgetFormReCaptchaTest.php";s:4:"role";s:4:"data";}}i:23;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"e04220de43865dc7cf4cc7fe5965873b";s:4:"name";s:18:"test/bootstrap.php";s:4:"role";s:4:"data";}}i:24;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"88def8417a8aefc9fa5d833a4f4d0373";s:4:"name";s:32:"web/css/jquery.autocompleter.css";s:4:"role";s:4:"data";}}i:25;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"460d935f81fd9de0c01656fd4f294757";s:4:"name";s:21:"web/js/double_list.js";s:4:"role";s:4:"data";}}i:26;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"b4dc9ff8b1a5569405fe53a1d4dd4f4e";s:4:"name";s:30:"web/js/jquery.autocompleter.js";s:4:"role";s:4:"data";}}i:27;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"03ce3dcc84af110e9da8699a841e5200";s:4:"name";s:24:"web/images/indicator.gif";s:4:"role";s:4:"data";}}i:28;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"64113e3f418860c6c27caa83d8494c73";s:4:"name";s:19:"web/images/next.png";s:4:"role";s:4:"data";}}i:29;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4485131fafbc7b6bd6018a67671e9040";s:4:"name";s:23:"web/images/previous.png";s:4:"role";s:4:"data";}}i:30;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"9c80350d278bfbcf24b946d86df8fab6";s:4:"name";s:6:"README";s:4:"role";s:4:"data";}}i:31;a:1:{s:7:"attribs";a:3:{s:6:"md5sum";s:32:"4db2c5c669396b6c794f2fe214cb33e8";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";}}}}}s:12:"dependencies";a:1:{s:8:"required";a:2:{s:3:"php";a:1:{s:3:"min";s:5:"5.2.4";}s:13:"pearinstaller";a:1:{s:3:"min";s:5:"1.4.1";}}}s:10:"phprelease";s:0:"";s:9:"changelog";a:1:{s:7:"release";a:4:{i:0;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.3";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}i:1;s:3:"MIT";}s:4:"date";s:10:"2010-08-25";s:5:"notes";s:575:"* xavier: allowed unassociated list to be left of the associated one (#7780) +* Fabien: added culture and theme options for sfWidgetFormReCaptcha (#8509) +* Fabien: updated the autocomplete JavaScript to the latest version +* Fabien: fixed sfWidgetFormJQueryDate doesn't refresh "disabled" after the date was chosen from calendar (#8817) +* Xavier: fixed sfWidgetFormJQueryDate doesn't restrict values on page load (#7792) +* Fabien: fixed JS function names when the widget name contains - (#8836) +* Fabien: added support for sfWidgetFormDateTime in sfWidgetFormJQueryDate (#8950)";}i:1;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.2";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}i:1;s:3:"MIT";}s:4:"date";s:10:"2010-08-03";s:5:"notes";s:314:"* Kris.Wallsmith: added sfValidatorDefault, which returns a default value rather than throw an error +* Kris.Wallsmith: fixed blacklist validator test +* FabianLange: fixed incorrect octal parsing of dates in javascript (#7743) +* Kris.Wallsmith: fixed reading of can_be_empty option in sfWidgetFormJQueryDate (#8723)";}i:2;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.1";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}i:1;s:3:"MIT";}s:4:"date";s:10:"2009-11-30";s:5:"notes";s:232:"* fabien: added a date_widget option to sfWidgetFormJQueryDate (#5382) +* fabien: changed the sfFormLanguage to take the current user culture into account (#6752) +* fabien: added sfWidgetFormDoctrineJQueryAutocompleter (#5118, #4943)";}i:3;a:5:{s:7:"version";a:2:{s:7:"release";s:5:"1.1.0";s:3:"api";s:5:"1.0.0";}s:9:"stability";a:2:{s:7:"release";s:6:"stable";s:3:"api";s:6:"stable";}s:7:"license";a:2:{i:0;a:2:{s:7:"attribs";a:1:{s:3:"uri";s:38:"http://www.symfony-project.com/license";}s:8:"_content";s:11:"MIT license";}i:1;s:3:"MIT";}s:4:"date";s:10:"2009-11-30";s:5:"notes";s:50:"* fabien: made the plugin work for symfony 1.3/1.4";}}}s:8:"filelist";a:32:{s:13:"bin/prove.php";a:4:{s:6:"md5sum";s:32:"dd477c00b9182a8fce0a2931b2afe14f";s:4:"name";s:13:"bin/prove.php";s:4:"role";s:4:"data";s:12:"installed_as";s:77:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/bin/prove.php";}s:33:"lib/form/sfFormLanguage.class.php";a:4:{s:6:"md5sum";s:32:"352b4711bca96a9ef711c02ba51a7487";s:4:"name";s:33:"lib/form/sfFormLanguage.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:97:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/form/sfFormLanguage.class.php";}s:66:"lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php";a:4:{s:6:"md5sum";s:32:"1374000a0198f4a174f80795e60e7c71";s:4:"name";s:66:"lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:130:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php";}s:44:"lib/validator/sfValidatorBlacklist.class.php";a:4:{s:6:"md5sum";s:32:"47573deff2c7264ae1a31ead15940eed";s:4:"name";s:44:"lib/validator/sfValidatorBlacklist.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/sfValidatorBlacklist.class.php";}s:44:"lib/validator/sfValidatorReCaptcha.class.php";a:4:{s:6:"md5sum";s:32:"71d741ed1a332e2c3c5e5eba43061123";s:4:"name";s:44:"lib/validator/sfValidatorReCaptcha.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:108:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/sfValidatorReCaptcha.class.php";}s:53:"lib/validator/sfValidatorSchemaTimeInterval.class.php";a:4:{s:6:"md5sum";s:32:"f1af2b598238238258888f18dbc8a257";s:4:"name";s:53:"lib/validator/sfValidatorSchemaTimeInterval.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:117:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/sfValidatorSchemaTimeInterval.class.php";}s:42:"lib/validator/sfValidatorDefault.class.php";a:4:{s:6:"md5sum";s:32:"122f99df59284f63338fd9a1e055e4ff";s:4:"name";s:42:"lib/validator/sfValidatorDefault.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:106:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/sfValidatorDefault.class.php";}s:54:"lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php";a:4:{s:6:"md5sum";s:32:"b0a625150802410c9a39dee434746908";s:4:"name";s:54:"lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:118:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php";}s:60:"lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php";a:4:{s:6:"md5sum";s:32:"8d3f91f1b54429c94b71517bd3840e20";s:4:"name";s:60:"lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:124:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php";}s:52:"lib/widget/sfWidgetFormJQueryAutocompleter.class.php";a:4:{s:6:"md5sum";s:32:"8ca49e7b709485623ebd124950a0a41f";s:4:"name";s:52:"lib/widget/sfWidgetFormJQueryAutocompleter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:116:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryAutocompleter.class.php";}s:43:"lib/widget/sfWidgetFormJQueryDate.class.php";a:4:{s:6:"md5sum";s:32:"0a004f96c83c50872775bcc698d5dabb";s:4:"name";s:43:"lib/widget/sfWidgetFormJQueryDate.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryDate.class.php";}s:52:"lib/widget/sfWidgetFormPropelChoiceGrouped.class.php";a:4:{s:6:"md5sum";s:32:"8c909201670d42f4d4ddfe46eab45adb";s:4:"name";s:52:"lib/widget/sfWidgetFormPropelChoiceGrouped.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:116:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelChoiceGrouped.class.php";}s:58:"lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php";a:4:{s:6:"md5sum";s:32:"45adc6b7bfb2296d7bc77a83a441ac88";s:4:"name";s:58:"lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:122:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php";}s:42:"lib/widget/sfWidgetFormReCaptcha.class.php";a:4:{s:6:"md5sum";s:32:"9feb211dbd9e4e274b7981f41af339cb";s:4:"name";s:42:"lib/widget/sfWidgetFormReCaptcha.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:106:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormReCaptcha.class.php";}s:49:"lib/widget/sfWidgetFormSelectDoubleList.class.php";a:4:{s:6:"md5sum";s:32:"83860c7eea89ef17f0e4d88268fbb7fc";s:4:"name";s:49:"lib/widget/sfWidgetFormSelectDoubleList.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:113:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectDoubleList.class.php";}s:46:"lib/widget/sfWidgetFormSelectUSState.class.php";a:4:{s:6:"md5sum";s:32:"4b4bedb41a4adb487ecc39cc47be4eab";s:4:"name";s:46:"lib/widget/sfWidgetFormSelectUSState.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:110:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectUSState.class.php";}s:48:"lib/widget/sfWidgetFormTextareaTinyMCE.class.php";a:4:{s:6:"md5sum";s:32:"b4e4b61fba61b26db3ac30bb5933771b";s:4:"name";s:48:"lib/widget/sfWidgetFormTextareaTinyMCE.class.php";s:4:"role";s:4:"data";s:12:"installed_as";s:112:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormTextareaTinyMCE.class.php";}s:32:"test/form/sfFormLanguageTest.php";a:4:{s:6:"md5sum";s:32:"ceecaca65fdf3b4c5e037ab6e696d06a";s:4:"name";s:32:"test/form/sfFormLanguageTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/form/sfFormLanguageTest.php";}s:43:"test/validator/sfValidatorReCaptchaTest.php";a:4:{s:6:"md5sum";s:32:"6ea19158046962f6ad76776ed3ad8673";s:4:"name";s:43:"test/validator/sfValidatorReCaptchaTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/validator/sfValidatorReCaptchaTest.php";}s:43:"test/validator/sfValidatorBlacklistTest.php";a:4:{s:6:"md5sum";s:32:"0c08b48fbc88fb98aa6062809cba54c8";s:4:"name";s:43:"test/validator/sfValidatorBlacklistTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:107:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/validator/sfValidatorBlacklistTest.php";}s:52:"test/validator/sfValidatorSchemaTimeIntervalTest.php";a:4:{s:6:"md5sum";s:32:"1f6fd7556f6f3a68b7a31ba859c4175b";s:4:"name";s:52:"test/validator/sfValidatorSchemaTimeIntervalTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:116:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/validator/sfValidatorSchemaTimeIntervalTest.php";}s:41:"test/validator/sfValidatorDefaultTest.php";a:4:{s:6:"md5sum";s:32:"92b4a5838358108197afe3afe8aee679";s:4:"name";s:41:"test/validator/sfValidatorDefaultTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/validator/sfValidatorDefaultTest.php";}s:41:"test/widget/sfWidgetFormReCaptchaTest.php";a:4:{s:6:"md5sum";s:32:"993dc134aefab7538455472af3a3c5a4";s:4:"name";s:41:"test/widget/sfWidgetFormReCaptchaTest.php";s:4:"role";s:4:"data";s:12:"installed_as";s:105:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/widget/sfWidgetFormReCaptchaTest.php";}s:18:"test/bootstrap.php";a:4:{s:6:"md5sum";s:32:"e04220de43865dc7cf4cc7fe5965873b";s:4:"name";s:18:"test/bootstrap.php";s:4:"role";s:4:"data";s:12:"installed_as";s:82:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/bootstrap.php";}s:32:"web/css/jquery.autocompleter.css";a:4:{s:6:"md5sum";s:32:"88def8417a8aefc9fa5d833a4f4d0373";s:4:"name";s:32:"web/css/jquery.autocompleter.css";s:4:"role";s:4:"data";s:12:"installed_as";s:96:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/css/jquery.autocompleter.css";}s:21:"web/js/double_list.js";a:4:{s:6:"md5sum";s:32:"460d935f81fd9de0c01656fd4f294757";s:4:"name";s:21:"web/js/double_list.js";s:4:"role";s:4:"data";s:12:"installed_as";s:85:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/js/double_list.js";}s:30:"web/js/jquery.autocompleter.js";a:4:{s:6:"md5sum";s:32:"b4dc9ff8b1a5569405fe53a1d4dd4f4e";s:4:"name";s:30:"web/js/jquery.autocompleter.js";s:4:"role";s:4:"data";s:12:"installed_as";s:94:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/js/jquery.autocompleter.js";}s:24:"web/images/indicator.gif";a:4:{s:6:"md5sum";s:32:"03ce3dcc84af110e9da8699a841e5200";s:4:"name";s:24:"web/images/indicator.gif";s:4:"role";s:4:"data";s:12:"installed_as";s:88:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/images/indicator.gif";}s:19:"web/images/next.png";a:4:{s:6:"md5sum";s:32:"64113e3f418860c6c27caa83d8494c73";s:4:"name";s:19:"web/images/next.png";s:4:"role";s:4:"data";s:12:"installed_as";s:83:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/images/next.png";}s:23:"web/images/previous.png";a:4:{s:6:"md5sum";s:32:"4485131fafbc7b6bd6018a67671e9040";s:4:"name";s:23:"web/images/previous.png";s:4:"role";s:4:"data";s:12:"installed_as";s:87:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/images/previous.png";}s:6:"README";a:4:{s:6:"md5sum";s:32:"9c80350d278bfbcf24b946d86df8fab6";s:4:"name";s:6:"README";s:4:"role";s:4:"data";s:12:"installed_as";s:70:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/README";}s:7:"LICENSE";a:4:{s:6:"md5sum";s:32:"4db2c5c669396b6c794f2fe214cb33e8";s:4:"name";s:7:"LICENSE";s:4:"role";s:4:"data";s:12:"installed_as";s:71:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/LICENSE";}}s:12:"_lastversion";N;s:7:"dirtree";a:15:{s:67:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/bin";b:1;s:63:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin";b:1;s:72:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/form";b:1;s:67:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib";b:1;s:86:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator/doctrine";b:1;s:77:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/validator";b:1;s:74:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/lib/widget";b:1;s:73:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/form";b:1;s:68:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test";b:1;s:78:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/validator";b:1;s:75:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/test/widget";b:1;s:71:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/css";b:1;s:67:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web";b:1;s:70:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/js";b:1;s:74:"/home/gustavo/symfonyreloaded/mobiads/plugins/sfFormExtraPlugin/web/images";b:1;}s:3:"old";a:7:{s:7:"version";s:5:"1.1.3";s:12:"release_date";s:10:"2010-08-25";s:13:"release_state";s:6:"stable";s:15:"release_license";s:11:"MIT license";s:13:"release_notes";s:1:"-";s:12:"release_deps";a:2:{i:0;a:4:{s:4:"type";s:3:"php";s:3:"rel";s:2:"ge";s:7:"version";s:5:"5.2.4";s:8:"optional";s:2:"no";}i:1;a:6:{s:4:"type";s:3:"pkg";s:7:"channel";s:12:"pear.php.net";s:4:"name";s:4:"PEAR";s:3:"rel";s:2:"ge";s:7:"version";s:5:"1.4.1";s:8:"optional";s:2:"no";}}s:11:"maintainers";a:4:{i:0;a:5:{s:4:"name";s:16:"Fabien Potencier";s:5:"email";s:36:"fabien.potencier@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:6:"fabpot";s:4:"role";s:4:"lead";}i:1;a:5:{s:4:"name";s:17:"Nicolas Perriault";s:5:"email";s:37:"nicolas.perriault@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:7:"nicolas";s:4:"role";s:9:"developer";}i:2;a:5:{s:4:"name";s:14:"Kris Wallsmith";s:5:"email";s:34:"kris.wallsmith@symfony-project.com";s:6:"active";s:3:"yes";s:6:"handle";s:14:"Kris.Wallsmith";s:4:"role";s:9:"developer";}i:3;a:5:{s:4:"name";s:10:"Hugo Hamon";s:5:"email";s:21:"hugo.hamon@sensio.com";s:6:"active";s:3:"yes";s:6:"handle";s:10:"hugo.hamon";s:4:"role";s:9:"developer";}}}s:10:"xsdversion";s:3:"2.0";s:13:"_lastmodified";i:1337219155;} \ No newline at end of file diff --git a/plugins/sfFormExtraPlugin/LICENSE b/plugins/sfFormExtraPlugin/LICENSE new file mode 100644 index 0000000..c5e65ea --- /dev/null +++ b/plugins/sfFormExtraPlugin/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008 Fabien Potencier + +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. diff --git a/plugins/sfFormExtraPlugin/README b/plugins/sfFormExtraPlugin/README new file mode 100644 index 0000000..7f15203 --- /dev/null +++ b/plugins/sfFormExtraPlugin/README @@ -0,0 +1,79 @@ +sfFormExtraPlugin +================= + +The `sfFormExtraPlugin` packages useful validators, widgets, and forms. + +This collection holds validators, widgets, and forms which we don't want to +include with the main symfony package because they are too specific or have +external dependencies. + +As no third party libraries is bundled in the plugin, you need to install and +load the required dependencies like JQuery, JQuery UI, or TinyMCE by yourself. + +Installation +------------ + + * Install the plugin + + $ symfony plugin:install sfFormExtraPlugin + + * Clear the cache + + $ symfony cache:clear + +Documentation +------------- + +All classes have full API and usage documentation. The best way to learn each widget or validator +is to read the API. + +You will also find some articles on the symfony blog about this plugin: + + * [Play with the user language](http://www.symfony-project.org/blog/2008/10/16/play-with-the-user-language) + * [Make your Choice!](http://www.symfony-project.org/blog/2008/10/14/new-in-symfony-1-2-make-your-choice) + * [Spice up your forms with some nice widgets and validators](http://www.symfony-project.org/blog/2008/10/18/spice-up-your-forms-with-some-nice-widgets-and-validators) + +Forms +----- + + * sfFormLanguage: A form to change the symfony user culture + +Validators +---------- + + * sfValidatorDoctrineNestedSetLevel: Checks wether or not the max level of a nested set object (nestedSet behavior) is achieved + * sfValidatorReCaptcha: Validates a ReCaptcha (see sfWidgetFormReCaptcha) + * sfValidatorBlacklist: Validates that a value is not one of the configured forbidden ones + * sfValidatorSchemaTimeInterval: Validates a time interval between two dates provided by a widget schema + * sfValidatorDefault: Returns a default value rather than throwing an error + +Widgets +------- + + * sfWidgetFormReCaptcha: Displays a ReCaptcha widget (see sfValidatorReCaptcha) + * sfWidgetFormSelectDoubleList: Displays a double list widget + * sfWidgetFormJQueryDate: Displays a date using JQuery UI + * sfWidgetFormJQueryAutocompleter: Displays an input tag with autocomplete support using JQuery + * sfWidgetFormPropelChoiceGrouped: Displays a grouped set of choices tied to a Propel model + * sfWidgetFormPropelJQueryAutocompleter: Displays an autocomplete widget tied to a Propel model + * sfWidgetFormTextareaTinyMCE: A rich textarea rendered with TinyMCE + * sfWidgetFormSelectUSState: A select menu of US states + +As no third party libraries is bundled in the plugin, you need to install and load the required +dependencies like JQuery, JQuery UI, or TinyMCE by yourself. + +How to contribute. +------------------ + +If you want to contribute a validator, a widget, or a form, follow these steps: + + * Check the prerequisites + * The license must be MIT + * You must have a unit test suite (100% coverage) + * You must have PHPdoc for all classes and methods with a documentation usage + * You must follow symfony coding standards + * The contribution must not be too specific + * You must be sure you will be able to maintain your contribution + * Create a ticket and attach a patch + * Choose `sfFormExtraPlugin` as the component + * Change the qualification to `Ready for core team` diff --git a/plugins/sfFormExtraPlugin/bin/prove.php b/plugins/sfFormExtraPlugin/bin/prove.php new file mode 100644 index 0000000..a508bbf --- /dev/null +++ b/plugins/sfFormExtraPlugin/bin/prove.php @@ -0,0 +1,16 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../test/bootstrap.php'; + +$h = new lime_harness(new lime_output_color()); +$h->base_dir = realpath(dirname(__FILE__).'/../test'); +$h->register(sfFinder::type('file')->name('*Test.php')->in($h->base_dir)); +$h->run(); diff --git a/plugins/sfFormExtraPlugin/lib/form/sfFormLanguage.class.php b/plugins/sfFormExtraPlugin/lib/form/sfFormLanguage.class.php new file mode 100644 index 0000000..3e9cfd0 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/form/sfFormLanguage.class.php @@ -0,0 +1,109 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfFormLanguage is a form to change the symfony user culture. + * + * Usage: + * + * class mainActions extends sfActions + * { + * public function executeChangeLanguage($request) + * { + * $this->form = new sfFormLanguage($this->getUser(), array('languages' => array('en', 'fr'))); + * if ($this->form->process($request)) + * { + * // culture has changed + * return $this->redirect('@homepage'); + * } + * + * // the form is not valid (can't happen... but you never know) + * return $this->redirect('@homepage'); + * } + * } + * + * @package symfony + * @subpackage form + * @author Fabien Potencier + * @version SVN: $Id: sfFormLanguage.class.php 30759 2010-08-25 11:48:01Z fabien $ + */ +class sfFormLanguage extends sfForm +{ + protected + $user = null; + + /** + * Constructor. + * + * @param sfUser A sfUser instance + * @param array An array of options + * @param string A CSRF secret (false to disable CSRF protection, null to use the global CSRF secret) + * + * @see sfForm + */ + public function __construct(sfUser $user, $options = array(), $CSRFSecret = null) + { + $this->user = $user; + + if (!isset($options['languages'])) + { + throw new RuntimeException(sprintf('%s requires a "languages" option.', get_class($this))); + } + + parent::__construct(array('language' => $user->getCulture()), $options, $CSRFSecret); + } + + /** + * Changes the current user culture. + */ + public function save() + { + $this->user->setCulture($this->getValue('language')); + } + + /** + * Processes the current request. + * + * @param sfRequest A sfRequest instance + * + * @return Boolean true if the form is valid, false otherwise + */ + public function process(sfRequest $request) + { + $data = array('language' => $request->getParameter('language')); + if ($request->hasParameter(self::$CSRFFieldName)) + { + $data[self::$CSRFFieldName] = $request->getParameter(self::$CSRFFieldName); + } + + $this->bind($data); + + if ($isValid = $this->isValid()) + { + $this->save(); + } + + return $isValid; + } + + /** + * @see sfForm + */ + public function configure() + { + $this->setValidators(array( + 'language' => new sfValidatorI18nChoiceLanguage(array('languages' => $this->options['languages'])), + )); + + $this->setWidgets(array( + 'language' => new sfWidgetFormI18nChoiceLanguage(array('culture' => $this->user->getCulture(), 'languages' => $this->options['languages'])), + )); + } +} diff --git a/plugins/sfFormExtraPlugin/lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php b/plugins/sfFormExtraPlugin/lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php new file mode 100644 index 0000000..b4fe010 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/validator/doctrine/sfValidatorDoctrineNestedSetLevel.class.php @@ -0,0 +1,140 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfValidatorDoctrineNestedSetLevel is a class that validates the max allowed + * depth level for Doctrine nested set objects. + * + * @package symfony + * @subpackage validator + * @author Hugo Hamon + */ +class sfValidatorDoctrineNestedSetLevel extends sfValidatorBase +{ + /** + * Configures the current validator. + * + * Available options: + * + * * max_level: The max depth to test (required integer) + * * model: The model class (required) + * * alias: The alias of the root component used in the query + * * query: A query to use when retrieving objects + * * column: The column name for the where clause statement (use primary key by default) + * * level_column: The level column name (use level by default) + * * connection: The Doctrine connection to use (null by default) + * + * Available error messages: + * + * * invalid: The related object has already the max level value + * * invalid_record: Unable to find the related object + * + * @see sfValidatorBase + */ + protected function configure($options = array(), $messages = array()) + { + $this->addRequiredOption('model'); + $this->addRequiredOption('max_level'); + $this->addOption('alias', 'a'); + $this->addOption('query', null); + $this->addOption('column', null); + $this->addOption('level_column', 'level'); + $this->addOption('connection', null); + + $this->addMessage('invalid_record', 'Unable to find the related record'); + } + + /** + * @see sfValidatorBase + * + * @throws sfValidatorError + */ + protected function doClean($value) + { + $level = $this->getObjectLevelValue($value); + + if ($level >= (int) $this->getOption('max_level')) + { + throw new sfValidatorError($this, 'invalid', array('value' => $level)); + } + + return $value; + } + + /** + * Returns the level column to use for comparison. + * + * The primary key is used by default. + * + * @return string The column name + */ + protected function getWhereColumn() + { + $table = $this->getDoctrineTable(); + + if ($this->getOption('column')) + { + return $table->getColumnName($this->getOption('column')); + } + + $identifier = (array) $table->getIdentifier(); + $columnName = current($identifier); + + return $table->getColumnName($columnName); + } + + /** + * Returns the level column name + * + * @return string The column name + */ + protected function getLevelColumn() + { + $table = $this->getDoctrineTable(); + + return $table->getColumnName($this->getOption('level_column')); + } + + /** + * Returns the Doctrine table object + * + * @return Doctrine_Table + */ + protected function getDoctrineTable() + { + return Doctrine::getTable($this->getOption('model')); + } + + /** + * Returns the object level's value + * + * @param mixed $value The value of the where column to retrieve the object + * + * @return int The level value of the found object + * + * @throws sfValidatorError + */ + protected function getObjectLevelValue($value) + { + $a = $this->getOption('alias'); + $q = is_null($this->getOption('query')) ? Doctrine_Query::create()->from($this->getOption('model') . ' ' . $a) : $this->getOption('query'); + $q->select($a . '.' . $this->getLevelColumn()); + $q->addWhere($a . '.' . $this->getWhereColumn() . ' = ?', $value); + + $result = $q->fetchOne(array(), Doctrine::HYDRATE_ARRAY); + + if (!$result) + { + throw new sfValidatorError($this, 'invalid_record', array('value' => $value)); + } + + return (int) $result[ $this->getLevelColumn() ]; + } +} \ No newline at end of file diff --git a/plugins/sfFormExtraPlugin/lib/validator/sfValidatorBlacklist.class.php b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorBlacklist.class.php new file mode 100644 index 0000000..a994763 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorBlacklist.class.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfValidatorBlacklist validates than the value is not one of the configured + * forbidden values. This is a kind of opposite of the sfValidatorChoice + * validator. + * + * @package symfony + * @subpackage validator + * @author Nicolas Perriault + * @version SVN: $Id: sfValidatorChoice.class.php 9048 2008-05-19 09:11:23Z FabianLange $ + */ +class sfValidatorBlacklist extends sfValidatorBase +{ + /** + * Configures the current validator. + * + * Available options: + * + * * forbidden_values: An array of forbidden values (required) + * * case_sensitive: Case sensitive comparison (default true) + * + * @param array $options An array of options + * @param array $messages An array of error messages + * + * @see sfValidatorBase + */ + protected function configure($options = array(), $messages = array()) + { + $this->addRequiredOption('forbidden_values'); + $this->addOption('case_sensitive', true); + $this->addMessage('forbidden', 'Value %value% is forbidden'); + } + + /** + * @see sfValidatorBase + */ + protected function doClean($value) + { + $forbiddenValues = $this->getOption('forbidden_values'); + if ($forbiddenValues instanceof sfCallable) + { + $forbiddenValues = $forbiddenValues->call(); + } + + $checkValue = $value; + + if (false === $this->getOption('case_sensitive')) + { + $checkValue = strtolower($checkValue); + $forbiddenValues = array_map('strtolower', $forbiddenValues); + } + + if (in_array($checkValue, $forbiddenValues)) + { + throw new sfValidatorError($this, 'forbidden', array('value' => $value)); + } + + return $value; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/validator/sfValidatorDefault.class.php b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorDefault.class.php new file mode 100644 index 0000000..5a3a096 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorDefault.class.php @@ -0,0 +1,76 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Returns a default value instead of throwing an error on validation failure. + * + * $this->validatorSchema['sort'] = new sfValidatorDefault(array( + * 'validator' => new sfValidatorChoice(array('choices' => array('up', 'down'))), + * 'default' => 'up', + * )); + * + * If no default option is provided, the supplied validator's empty value will + * be returned on error. + * + * @package sfFormExtraPlugin + * @subpackage validator + * @author Kris Wallsmith + * @version SVN: $Id: sfValidatorDefault.class.php 27625 2010-02-06 22:07:40Z Kris.Wallsmith $ + */ +class sfValidatorDefault extends sfValidatorBase +{ + /** + * Configures the current validator. + * + * Available options: + * + * * validator: The validator to use + * * default: The value to return if the validator fails + * + * @see sfValidatorBase + */ + protected function configure($options = array(), $messages = array()) + { + $this->addRequiredOption('validator'); + $this->addOption('default', null); + } + + /** + * @see sfValidatorBase + */ + protected function isEmpty($value) + { + return false; + } + + /** + * @see sfValidatorBase + * + * @throws InvalidArgumentException If the validator option is not a validator object + */ + protected function doClean($value) + { + $validator = $this->getOption('validator'); + + if (!$validator instanceof sfValidatorBase) + { + throw new InvalidArgumentException('The "validator" option must be an instance of sfValidatorBase.'); + } + + try + { + return $validator->clean($value); + } + catch (sfValidatorError $error) + { + return null === $this->getOption('default') ? $validator->getEmptyValue() : $this->getOption('default'); + } + } +} diff --git a/plugins/sfFormExtraPlugin/lib/validator/sfValidatorReCaptcha.class.php b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorReCaptcha.class.php new file mode 100644 index 0000000..f46845c --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorReCaptcha.class.php @@ -0,0 +1,134 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfValidatorReCaptcha validates a ReCaptcha. + * + * This validator uses ReCaptcha: http://recaptcha.net/ + * + * The ReCaptcha API documentation can be found at http://recaptcha.net/apidocs/captcha/ + * + * To be able to use this validator, you need an API key: http://recaptcha.net/api/getkey + * + * To create a captcha validator: + * + * $captcha = new sfValidatorReCaptcha(array('private_key' => RECAPTCHA_PRIVATE_KEY)); + * + * where RECAPTCHA_PRIVATE_KEY is the ReCaptcha private key. + * + * @package symfony + * @subpackage validator + * @author Fabien Potencier + * @version SVN: $Id: sfValidatorReCaptcha.class.php 7903 2008-03-15 13:17:41Z fabien $ + */ +class sfValidatorReCaptcha extends sfValidatorBase +{ + /** + * Configures the current validator. + * + * Available options: + * + * * private_key: The ReCaptcha private key (required) + * * remote_addr: The remote address of the user + * * server_host: The ReCaptcha server host + * * server_port: The ReCaptcha server port + * * server_path: The ReCatpcha server path + * * server_timeout: The timeout to use when contacting the ReCaptcha server + * + * Available error codes: + * + * * captcha + * * server_problem + * + * @see sfValidatorBase + */ + protected function configure($options = array(), $messages = array()) + { + $this->addRequiredOption('private_key'); + + $this->addOption('remote_addr'); + $this->addOption('server_host', 'api-verify.recaptcha.net'); + $this->addOption('server_port', 80); + $this->addOption('server_path', '/verify'); + $this->addOption('server_timeout', 10); + + $this->addMessage('captcha', 'The captcha is not valid (%error%).'); + $this->addMessage('server_problem', 'Unable to check the captcha from the server (%error%).'); + } + + /** + * Cleans the input value. + * + * The input value must be an array with 2 required keys: recaptcha_challenge_field and recaptcha_response_field. + * + * It always returns null. + * + * @see sfValidatorBase + */ + protected function doClean($value) + { + $challenge = isset($value['recaptcha_challenge_field']) ? $value['recaptcha_challenge_field'] : null; + $response = isset($value['recaptcha_response_field']) ? $value['recaptcha_response_field'] : null; + if (empty($challenge) || empty($response)) + { + throw new sfValidatorError($this, 'captcha', array('error' => 'invalid captcha')); + } + + if (true !== ($answer = $this->check(array( + 'privatekey' => $this->getOption('private_key'), + 'remoteip' => $this->getOption('remote_addr') ? $this->getOption('remote_addr') : $_SERVER['REMOTE_ADDR'], + 'challenge' => $challenge, + 'response' => $response, + )))) + { + throw new sfValidatorError($this, 'captcha', array('error' => $answer)); + } + + return null; + } + + /** + * Returns true if the captcha is valid. + * + * @param array An array of request parameters + * + * @return Boolean true if the captcha is valid, false otherwise + */ + protected function check($parameters) + { + if (false === ($fs = @fsockopen($this->getOption('server_host'), $this->getOption('server_port'), $errno, $errstr, $this->getOption('server_timeout')))) + { + throw new sfValidatorError($this, 'server_problem', array('error' => $errstr)); + } + + $query = http_build_query($parameters, null, '&'); + fwrite($fs, sprintf( + "POST %s HTTP/1.0\r\n". + "Host: %s\r\n". + "Content-Type: application/x-www-form-urlencoded\r\n". + "Content-Length: %d\r\n". + "User-Agent: reCAPTCHA/PHP/symfony\r\n". + "\r\n%s", + $this->getOption('server_path'), $this->getOption('server_host'), strlen($query), $query) + ); + + $response = ''; + while (!feof($fs)) + { + $response .= fgets($fs, 1160); + } + fclose($fs); + + $response = explode("\r\n\r\n", $response, 2); + $answers = explode("\n", $response[1]); + + return 'true' == trim($answers[0]) ? true : $answers[1]; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/validator/sfValidatorSchemaTimeInterval.class.php b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorSchemaTimeInterval.class.php new file mode 100644 index 0000000..c042dd1 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/validator/sfValidatorSchemaTimeInterval.class.php @@ -0,0 +1,180 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * This schema validator validates a time interval between two dates, provided + * by two fields in the schema. + * + * Several options are available: + * + * - date_start_field: The start date field name + * - date_end_field: The end date field name + * - min_duration: The minimum duration of interval between the two dates, in seconds (optional) + * - max_duration: The maximum duration of interval between the two dates, in seconds (optional) + * - disallow_future_dates: Disallows dates in the future (defaults to false) + * - disallow_past_dates: Disallows dates in the past (defaults to false) + * - throw_global_error: Throws a global error (defaults to false) + * + * These error codes are available: + * + * - future_date: A date is in the future + * - past_date: A date is in the past + * - start_not_prior: The start date is not prior to end date + * - too_short: The duration is too short + * - too_long: The maximum duration has been exceeded + * + * Error messages available arguments: + * + * - date_start: The submitted start date + * - date_end: The submitted end date + * + * @package symfony + * @subpackage validator + * @author Nicolas Perriault + */ +class sfValidatorSchemaTimeInterval extends sfValidatorSchema +{ + protected + $dateStart = null, + $dateEnd = null; + + /** + * Public constructor + * + * @param string $dateStartField The name of the start date field + * @param string $dateEndField The name of the end date field + * @param array $options Options array + * @param array $messages Error messages array + */ + public function __construct($dateStartField, $dateEndField, $options = array(), $messages = array()) + { + // Validator options + $this->addOption('date_start_field', $dateStartField); + $this->addOption('date_end_field', $dateEndField); + $this->addOption('min_duration', null); + $this->addOption('max_duration', null); + $this->addOption('disallow_future_dates', false); + $this->addOption('disallow_past_dates', false); + $this->addOption('throw_global_error', false); + + // Validation error messages + $this->addMessage('future_date', 'The date cannot be in the future'); + $this->addMessage('past_date', 'The date cannot be in the past'); + $this->addMessage('too_short', 'The time interval between the two dates is too short'); + $this->addMessage('too_long', 'The time interval between the two dates is too long'); + $this->addMessage('start_not_prior', 'The start date must be prior to the end date'); + + // Parent constructor call + parent::__construct(null, $options, $messages); + } + + /** + * Cleans the schema values + * + * @see sfValidatorSchema + * + * @param array $values Values to validate + * @return array + * @throws InvalidArgumentException if $values is not an array + * @throws sfValidatorError + * @throws sfValidatorErrorSchema + */ + protected function doClean($values) + { + if (is_null($values)) + { + $values = array(); + } + + if (!is_array($values)) + { + throw new InvalidArgumentException('You must pass an array parameter to the clean() method'); + } + + $this->dateStart = isset($values[$this->getOption('date_start_field')]) ? strtotime($values[$this->getOption('date_start_field')]) : null; + $this->dateEnd = isset($values[$this->getOption('date_end_field')]) ? strtotime($values[$this->getOption('date_end_field')]) : null; + + $errorCode = null; + $errorField = null; + + if ($this->getOption('disallow_future_dates')) + { + if (!is_null($this->dateStart) && $this->dateStart > time()) + { + $this->throwError('future_date', $this->getOption('date_start_field')); + } + else if (!is_null($this->dateEnd) && $this->dateEnd > time()) + { + $this->throwError('future_date', $this->getOption('date_end_field')); + } + } + + if ($this->getOption('disallow_past_dates')) + { + if (!is_null($this->dateStart) && $this->dateStart < time()) + { + $this->throwError('past_date', $this->getOption('date_start_field')); + } + else if (!is_null($this->dateEnd) && $this->dateEnd < time()) + { + $this->throwError('past_date', $this->getOption('date_end_field')); + } + } + + // At this point, if either the start or end date is not set we can return values + if (is_null($this->dateStart) or is_null($this->dateEnd)) + { + return $values; + } + + // Duration + $duration = $this->dateEnd - $this->dateStart; + + if ($this->hasOption('min_duration') && $duration < $this->getOption('min_duration')) + { + $this->throwError('too_short', $this->getOption('date_end_field')); + } + + if ($this->hasOption('max_duration') && $duration > $this->getOption('max_duration')) + { + $this->throwError('too_long', $this->getOption('date_end_field')); + } + + if ($this->dateStart > $this->dateEnd) + { + $this->throwError('start_not_prior', $this->getOption('date_start_field')); + } + + return $values; + } + + /** + * Throws a validation error + * + * @param string $code The error code + * @param string $field The field related to the error + * @throws sfValidatorError + * @throws sfValidatorErrorSchema + */ + protected function throwError($code, $field) + { + $error = new sfValidatorError($this, $code, array( + 'date_start' => date('Y-m-d', $this->dateStart), + 'date_end' => date('Y-m-d', $this->dateEnd), + )); + + if ($this->getOption('throw_global_error')) + { + throw $error; + } + + throw new sfValidatorErrorSchema($this, array($field => $error)); + } +} \ No newline at end of file diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php new file mode 100644 index 0000000..02ffc49 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineChoiceGrouped.class.php @@ -0,0 +1,91 @@ + + * @version SVN: $Id: sfWidgetFormDoctrineChoiceGrouped.class.php 16265 2009-03-12 15:23:41Z Kris.Wallsmith $ + */ +class sfWidgetFormDoctrineChoiceGrouped extends sfWidgetFormDoctrineChoice +{ + /** + * Available options: + * + * * group_by: The name of the relation to use for grouping + * + * @see sfWidget + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('group_by'); + + parent::configure($options, $attributes); + } + + /** + * @see sfWidgetFormDoctrineChoice + */ + public function getChoices() + { + if (is_null($this->getOption('table_method'))) + { + $query = is_null($this->getOption('query')) ? Doctrine::getTable($this->getOption('model'))->createQuery() : $this->getOption('query'); + + if ($order = $this->getOption('order_by')) + { + $query->addOrderBy($order[0].' '.$order[1]); + } + + $objects = $query->execute(); + } + else + { + $tableMethod = $this->getOption('table_method'); + $results = Doctrine::getTable($this->getOption('model'))->$tableMethod(); + + if ($results instanceof Doctrine_Query) + { + $objects = $results->execute(); + } + else if ($results instanceof Doctrine_Collection) + { + $objects = $results; + } + else if ($results instanceof Doctrine_Record) + { + $objects = new Doctrine_Collection($this->getOption('model')); + $objects[] = $results; + } + else + { + $objects = array(); + } + } + + $choices = array(); + if (false !== $this->getOption('add_empty')) + { + $choices[''] = true === $this->getOption('add_empty') ? '' : $this->getOption('add_empty'); + } + + $method = $this->getOption('method'); + $keyMethod = $this->getOption('key_method'); + $groupBy = $this->getOption('group_by'); + + foreach ($objects as $object) + { + $parent = (string) $object->$groupBy; + + if (!isset($choices[$parent])) + { + $choices[$parent] = array(); + } + + $choices[$parent][$object->$keyMethod()] = $object->$method(); + } + + return $choices; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php new file mode 100644 index 0000000..c05854e --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormDoctrineJQueryAutocompleter.class.php @@ -0,0 +1,77 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormDoctrineJQueryAutocompleter represents an autocompleter input widget rendered by JQuery + * optimized for foreign key lookup. + * + * This implementation is based on sfWidgetFormPropelJQueryAutocompleter. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @author Roland Jungwirth + * @version SVN: $Id: sfWidgetFormPropelJQueryAutocompleter.class.php 12130 2008-10-10 14:51:07Z fabien $ + */ +class sfWidgetFormDoctrineJQueryAutocompleter extends sfWidgetFormJQueryAutocompleter +{ + /** + * @see sfWidget + */ + public function __construct($options = array(), $attributes = array()) + { + $options['value_callback'] = array($this, 'toString'); + + parent::__construct($options, $attributes); + } + + /** + * Configures the current widget. + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetFormJQueryAutocompleter + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('model'); + $this->addOption('method_for_query', 'findOneById'); + $this->addOption('method', '__toString'); + + parent::configure($options, $attributes); + } + + /** + * Returns the text representation of a foreign key. + * + * @param string $value The primary key + */ + protected function toString($value) + { + $object = null; + if ($value != null) + { + $class = Doctrine::getTable($this->getOption('model')); + $method = $this->getOption('method_for_query'); + + $object = call_user_func(array($class, $method), $value); + } + + $method = $this->getOption('method'); + + if (!method_exists($this->getOption('model'), $method)) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "%s" method to be rendered in a "%s" widget', $this->getOption('model'), $method, __CLASS__)); + } + + return !is_null($object) ? $object->$method() : ''; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryAutocompleter.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryAutocompleter.class.php new file mode 100644 index 0000000..d66b09b --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryAutocompleter.class.php @@ -0,0 +1,115 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormJQueryAutocompleter represents an autocompleter input widget rendered by JQuery. + * + * This widget needs JQuery to work. + * + * You also need to include the JavaScripts and stylesheets files returned by the getJavaScripts() + * and getStylesheets() methods. + * + * If you use symfony 1.2, it can be done automatically for you. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormJQueryAutocompleter.class.php 15839 2009-02-27 05:40:57Z fabien $ + */ +class sfWidgetFormJQueryAutocompleter extends sfWidgetFormInput +{ + /** + * Configures the current widget. + * + * Available options: + * + * * url: The URL to call to get the choices to use (required) + * * config: A JavaScript array that configures the JQuery autocompleter widget + * * value_callback: A callback that converts the value before it is displayed + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetForm + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('url'); + $this->addOption('value_callback'); + $this->addOption('config', '{ }'); + + // this is required as it can be used as a renderer class for sfWidgetFormChoice + $this->addOption('choices'); + + parent::configure($options, $attributes); + } + + /** + * @param string $name The element name + * @param string $value The date displayed in this widget + * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes + * @param array $errors An array of errors for the field + * + * @return string An HTML tag string + * + * @see sfWidgetForm + */ + public function render($name, $value = null, $attributes = array(), $errors = array()) + { + $visibleValue = $this->getOption('value_callback') ? call_user_func($this->getOption('value_callback'), $value) : $value; + + return $this->renderTag('input', array('type' => 'hidden', 'name' => $name, 'value' => $value)). + parent::render('autocomplete_'.$name, $visibleValue, $attributes, $errors). + sprintf(<< + jQuery(document).ready(function() { + jQuery("#%s") + .autocomplete('%s', jQuery.extend({}, { + dataType: 'json', + parse: function(data) { + var parsed = []; + for (key in data) { + parsed[parsed.length] = { data: [ data[key], key ], value: data[key], result: data[key] }; + } + return parsed; + } + }, %s)) + .result(function(event, data) { jQuery("#%s").val(data[1]); }); + }); + +EOF + , + $this->generateId('autocomplete_'.$name), + $this->getOption('url'), + $this->getOption('config'), + $this->generateId($name) + ); + } + + /** + * Gets the stylesheet paths associated with the widget. + * + * @return array An array of stylesheet paths + */ + public function getStylesheets() + { + return array('/sfFormExtraPlugin/css/jquery.autocompleter.css' => 'all'); + } + + /** + * Gets the JavaScript paths associated with the widget. + * + * @return array An array of JavaScript paths + */ + public function getJavascripts() + { + return array('/sfFormExtraPlugin/js/jquery.autocompleter.js'); + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryDate.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryDate.class.php new file mode 100644 index 0000000..f73bb8b --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormJQueryDate.class.php @@ -0,0 +1,148 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormJQueryDate represents a date widget rendered by JQuery UI. + * + * This widget needs JQuery and JQuery UI to work. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormJQueryDate.class.php 30755 2010-08-25 11:14:33Z fabien $ + */ +class sfWidgetFormJQueryDate extends sfWidgetForm +{ + /** + * Configures the current widget. + * + * Available options: + * + * * image: The image path to represent the widget (false by default) + * * config: A JavaScript array that configures the JQuery date widget + * * culture: The user culture + * * date_widget: The date widget instance to use as a "base" class + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetForm + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addOption('image', false); + $this->addOption('config', '{}'); + $this->addOption('culture', ''); + $this->addOption('date_widget', new sfWidgetFormDate()); + + parent::configure($options, $attributes); + + if ('en' == $this->getOption('culture')) + { + $this->setOption('culture', 'en'); + } + } + + /** + * @param string $name The element name + * @param string $value The date displayed in this widget + * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes + * @param array $errors An array of errors for the field + * + * @return string An HTML tag string + * + * @see sfWidgetForm + */ + public function render($name, $value = null, $attributes = array(), $errors = array()) + { + $prefix = str_replace('-', '_', $this->generateId($name)); + + $image = ''; + if (false !== $this->getOption('image')) + { + $image = sprintf(', buttonImage: "%s", buttonImageOnly: true', $this->getOption('image')); + } + + if ($this->getOption('date_widget') instanceof sfWidgetFormDateTime) + { + $years = $this->getOption('date_widget')->getDateWidget()->getOption('years'); + } + else + { + $years = $this->getOption('date_widget')->getOption('years'); + } + + return $this->getOption('date_widget')->render($name, $value, $attributes, $errors). + $this->renderTag('input', array('type' => 'hidden', 'size' => 10, 'id' => $id = $this->generateId($name).'_jquery_control', 'disabled' => 'disabled')). + sprintf(<< + function wfd_%s_read_linked() + { + jQuery("#%s").val(jQuery("#%s").val() + "-" + jQuery("#%s").val() + "-" + jQuery("#%s").val()); + + return {}; + } + + function wfd_%s_update_linked(date) + { + jQuery("#%s").val(parseInt(date.substring(0, 4), 10)); + jQuery("#%s").val(parseInt(date.substring(5, 7), 10)); + jQuery("#%s").val(parseInt(date.substring(8), 10)); + + wfd_%s_check_linked_days(); + } + + function wfd_%s_check_linked_days() + { + var daysInMonth = 32 - new Date(jQuery("#%s").val(), jQuery("#%s").val() - 1, 32).getDate(); + + jQuery("#%s option").attr("disabled", ""); + jQuery("#%s option:gt(" + (%s) +")").attr("disabled", "disabled"); + + if (jQuery("#%s").val() > daysInMonth) + { + jQuery("#%s").val(daysInMonth); + } + } + + jQuery(document).ready(function() { + jQuery("#%s").datepicker(jQuery.extend({}, { + minDate: new Date(%s, 1 - 1, 1), + maxDate: new Date(%s, 12 - 1, 31), + beforeShow: wfd_%s_read_linked, + onSelect: wfd_%s_update_linked, + showOn: "button" + %s + }, jQuery.datepicker.regional["%s"], %s, {dateFormat: "yy-mm-dd"})); + wfd_%s_check_linked_days(); + }); + + jQuery("#%s, #%s, #%s").change(wfd_%s_check_linked_days); + +EOF + , + $prefix, $id, + $this->generateId($name.'[year]'), $this->generateId($name.'[month]'), $this->generateId($name.'[day]'), + $prefix, + $this->generateId($name.'[year]'), $this->generateId($name.'[month]'), $this->generateId($name.'[day]'), + $prefix, $prefix, + $this->generateId($name.'[year]'), $this->generateId($name.'[month]'), + $this->generateId($name.'[day]'), $this->generateId($name.'[day]'), + ($this->getOption('date_widget')->getOption('can_be_empty') ? 'daysInMonth' : 'daysInMonth - 1'), + $this->generateId($name.'[day]'), $this->generateId($name.'[day]'), + $id, + min($years), max($years), + $prefix, $prefix, $image, $this->getOption('culture'), $this->getOption('config'), + $prefix, + $this->generateId($name.'[day]'), $this->generateId($name.'[month]'), $this->generateId($name.'[year]'), + $prefix + ); + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelChoiceGrouped.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelChoiceGrouped.class.php new file mode 100644 index 0000000..644ba29 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelChoiceGrouped.class.php @@ -0,0 +1,92 @@ + + * @version SVN: $Id: sfWidgetFormPropelChoiceGrouped.class.php 16067 2009-03-06 16:57:46Z Kris.Wallsmith $ + */ +class sfWidgetFormPropelChoiceGrouped extends sfWidgetFormPropelChoice +{ + /** + * Available options: + * + * * group_by_method: A method on the current model that will return the + * object the widget is grouped by (i.e. getAuthor) + * + * @see sfWidget + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('group_by_method'); + + parent::configure($options, $attributes); + } + + /** + * @see sfWidgetFormPropelChoice + */ + public function getChoices() + { + $choices = array(); + if (!$this->getOption('expanded') && false !== $this->getOption('add_empty')) + { + $choices[''] = true === $this->getOption('add_empty') ? '' : $this->getOption('add_empty'); + } + + $methodKey = $this->getOption('key_method'); + if (!method_exists($this->getOption('model'), $methodKey)) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "%s" method to be rendered in a "%s" widget', $this->getOption('model'), $methodKey, __CLASS__)); + } + + $methodValue = $this->getOption('method'); + if (!method_exists($this->getOption('model'), $methodValue)) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "%s" method to be rendered in a "%s" widget', $this->getOption('model'), $methodValue, __CLASS__)); + } + + $methodParent = $this->getOption('group_by_method'); + if (!method_exists($this->getOption('model'), $methodParent)) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "%s" method to be rendered in a "%s" widget', $this->getOption('model'), $methodParent, __CLASS__)); + } + + $class = constant($this->getOption('model').'::PEER'); + + $criteria = is_null($this->getOption('criteria')) ? new Criteria() : clone $this->getOption('criteria'); + if ($order = $this->getOption('order_by')) + { + $method = sprintf('add%sOrderByColumn', 0 === strpos(strtoupper($order[1]), 'ASC') ? 'Ascending' : 'Descending'); + $criteria->$method(call_user_func(array($class, 'translateFieldName'), $order[0], BasePeer::TYPE_PHPNAME, BasePeer::TYPE_COLNAME)); + } + + if ('doSelect' == $peerMethod = $this->getOption('peer_method')) + { + // apply join method + $peerMethod = 'doSelectJoin'.substr($this->getOption('group_by_method'), 3); + } + $objects = call_user_func(array($class, $peerMethod), $criteria, $this->getOption('connection')); + + foreach ($objects as $object) + { + $parent = $object->$methodParent($this->getOption('connection')); + if (!method_exists($parent, '__toString')) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "__toString" method to be rendered in a "%s" widget', get_class($parent), __CLASS__)); + } + + $parentValue = (string) $parent; + if (!isset($choices[$parentValue])) + { + $choices[$parentValue] = array(); + } + + $choices[$parentValue][$object->$methodKey()] = $object->$methodValue(); + } + + return $choices; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php new file mode 100644 index 0000000..14a88d7 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormPropelJQueryAutocompleter.class.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormPropelJQueryAutocompleter represents an autocompleter input widget rendered by JQuery + * optimized for foreign key lookup. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormPropelJQueryAutocompleter.class.php 12130 2008-10-10 14:51:07Z fabien $ + */ +class sfWidgetFormPropelJQueryAutocompleter extends sfWidgetFormJQueryAutocompleter +{ + /** + * @see sfWidget + */ + public function __construct($options = array(), $attributes = array()) + { + $options['value_callback'] = array($this, 'toString'); + + parent::__construct($options, $attributes); + } + + /** + * Configures the current widget. + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetFormJQueryAutocompleter + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('model'); + $this->addOption('method', '__toString'); + + parent::configure($options, $attributes); + } + + /** + * Returns the text representation of a foreign key. + * + * @param string $value The primary key + */ + protected function toString($value) + { + $class = constant($this->getOption('model').'::PEER'); + + $criteria = new Criteria(); + $object = call_user_func(array($class, 'retrieveByPK'), $value); + + $method = $this->getOption('method'); + + if (!method_exists($this->getOption('model'), $method)) + { + throw new RuntimeException(sprintf('Class "%s" must implement a "%s" method to be rendered in a "%s" widget', $this->getOption('model'), $method, __CLASS__)); + } + + return !is_null($object) ? $object->$method() : ''; + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormReCaptcha.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormReCaptcha.class.php new file mode 100644 index 0000000..adc51ef --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormReCaptcha.class.php @@ -0,0 +1,93 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormReCaptcha renders a ReCaptcha widget. + * + * This widget uses ReCaptcha: http://recaptcha.net/ + * + * The ReCaptcha API documentation can be found at http://recaptcha.net/apidocs/captcha/ + * + * To be able to use this widget, you need an API key: http://recaptcha.net/api/getkey + * + * As it's not possible to change the name of ReCaptcha fields, you will have to add them manually + * when binding a form from an HTTP request. + * + * Here's a typical usage when embedding a captcha in a form with a contact[%s] name format: + * + * $captcha = array( + * 'recaptcha_challenge_field' => $request->getParameter('recaptcha_challenge_field'), + * 'recaptcha_response_field' => $request->getParameter('recaptcha_response_field'), + * ); + * $this->form->bind(array_merge($request->getParameter('contact'), array('captcha' => $captcha))); + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormReCaptcha.class.php 30758 2010-08-25 11:39:13Z fabien $ + */ +class sfWidgetFormReCaptcha extends sfWidgetForm +{ + /** + * Configures the current widget. + * + * Available options: + * + * * public_key: The ReCaptcha public key + * * use_ssl: Whether to use SSL or not (false by default) + * * server_url: The URL for the HTTP API + * * server_url_ssl: The URL for the HTTPS API (when use_ssl is true) + * * theme: The ReCaptcha theme + * * culture: The ReCaptcha language + * + * @see sfWidgetForm + */ + public function configure($options = array(), $messages = array()) + { + $this->addRequiredOption('public_key'); + + $this->addOption('use_ssl', false); + $this->addOption('server_url', 'http://api.recaptcha.net'); + $this->addOption('server_url_ssl', 'https://api-secure.recaptcha.net'); + $this->addOption('theme', 'clean'); + $this->addOption('culture', 'en'); + } + + /** + * @see sfWidgetForm + */ + public function render($name, $value = null, $attributes = array(), $errors = array()) + { + $server = $this->getServerUrl(); + $key = $this->getOption('public_key'); + $theme = $this->getOption('theme'); + $culture = $this->getOption('culture'); + + return sprintf(' + + + + ', $theme, $culture, $server, $key, $server, $key); + } + + protected function getServerUrl() + { + return $this->getOption('use_ssl') ? $this->getOption('server_url_ssl') : $this->getOption('server_url'); + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectDoubleList.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectDoubleList.class.php new file mode 100644 index 0000000..24c6c64 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectDoubleList.class.php @@ -0,0 +1,185 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormSelectDoubleList represents a multiple select displayed as a double list. + * + * This widget needs some JavaScript to work. So, you need to include the JavaScripts + * files returned by the getJavaScripts() method. + * + * If you use symfony 1.2, it can be done automatically for you. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormSelectDoubleList.class.php 30760 2010-08-25 11:50:26Z fabien $ + */ +class sfWidgetFormSelectDoubleList extends sfWidgetForm +{ + /** + * Constructor. + * + * Available options: + * + * * choices: An array of possible choices (required) + * * class: The main class of the widget + * * class_select: The class for the two select tags + * * label_unassociated: The label for unassociated + * * label_associated: The label for associated + * * unassociate: The HTML for the unassociate link + * * associate: The HTML for the associate link + * * associated_first: Whether the associated list if first (true by default) + * * template: The HTML template to use to render this widget + * The available placeholders are: + * * label_associated + * * label_unassociated + * * associate + * * unassociate + * * associated + * * unassociated + * * class + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetForm + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addRequiredOption('choices'); + + $this->addOption('class', 'double_list'); + $this->addOption('class_select', 'double_list_select'); + $this->addOption('associated_first', true); + $this->addOption('label_unassociated', 'Unassociated'); + $this->addOption('label_associated', 'Associated'); + $associated_first = isset($options['associated_first']) ? $options['associated_first'] : true; + + if ($associated_first) + { + $associate_image = 'previous.png'; + $unassociate_image = 'next.png'; + $float = 'left'; + } + else + { + $associate_image = 'next.png'; + $unassociate_image = 'previous.png'; + $float = 'right'; + } + + $this->addOption('unassociate', 'unassociate'); + $this->addOption('associate', 'associate'); + $this->addOption('template', << +
+
+
%label_associated%
+ %associated% +
+
+ %associate% +
+ %unassociate% +
+
+
%label_unassociated%
+ %unassociated% +
+
+
+ + +EOF +); + } + + /** + * Renders the widget. + * + * @param string $name The element name + * @param string $value The value selected in this widget + * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes + * @param array $errors An array of errors for the field + * + * @return string An HTML tag string + * + * @see sfWidgetForm + */ + public function render($name, $value = null, $attributes = array(), $errors = array()) + { + if (is_null($value)) + { + $value = array(); + } + + $choices = $this->getOption('choices'); + if ($choices instanceof sfCallable) + { + $choices = $choices->call(); + } + + $associated = array(); + $unassociated = array(); + foreach ($choices as $key => $option) + { + if (in_array(strval($key), $value)) + { + $associated[$key] = $option; + } + else + { + $unassociated[$key] = $option; + } + } + + $size = isset($attributes['size']) ? $attributes['size'] : (isset($this->attributes['size']) ? $this->attributes['size'] : 10); + + $associatedWidget = new sfWidgetFormSelect(array('multiple' => true, 'choices' => $associated), array('size' => $size, 'class' => $this->getOption('class_select').'-selected')); + $unassociatedWidget = new sfWidgetFormSelect(array('multiple' => true, 'choices' => $unassociated), array('size' => $size, 'class' => $this->getOption('class_select'))); + + return strtr($this->getOption('template'), array( + '%class%' => $this->getOption('class'), + '%class_select%' => $this->getOption('class_select'), + '%id%' => $this->generateId($name), + '%label_associated%' => $this->getOption('label_associated'), + '%label_unassociated%' => $this->getOption('label_unassociated'), + '%associate%' => sprintf('%s', 'sfDoubleList.move(\'unassociated_'.$this->generateId($name).'\', \''.$this->generateId($name).'\'); return false;', $this->getOption('associate')), + '%unassociate%' => sprintf('%s', 'sfDoubleList.move(\''.$this->generateId($name).'\', \'unassociated_'.$this->generateId($name).'\'); return false;', $this->getOption('unassociate')), + '%associated%' => $associatedWidget->render($name), + '%unassociated%' => $unassociatedWidget->render('unassociated_'.$name), + )); + } + + /** + * Gets the JavaScript paths associated with the widget. + * + * @return array An array of JavaScript paths + */ + public function getJavascripts() + { + return array('/sfFormExtraPlugin/js/double_list.js'); + } + + public function __clone() + { + if ($this->getOption('choices') instanceof sfCallable) + { + $callable = $this->getOption('choices')->getCallable(); + if (is_array($callable)) + { + $callable[0] = $this; + $this->setOption('choices', new sfCallable($callable)); + } + } + } +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectUSState.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectUSState.class.php new file mode 100644 index 0000000..9be3f82 --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormSelectUSState.class.php @@ -0,0 +1,152 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * Select menu of US states. + * + * Here's an example usage: + * + * $this->setWidgets(array( + * 'state' => new sfWidgetFormSelectUSState(array('add_empty' => 'Select a state...')), + * )); + * + * $this->setValidators(array( + * 'state' => sfValidatorChoice(array('choices' => sfWidgetFormSelectUSState::getStateAbbreviations())), + * )); + * + * @package sfFormExtraPlugin + * @subpackage widget + * @author Kris Wallsmith + * @version SVN: $Id: sfWidgetFormSelectUSState.class.php 15371 2009-02-09 19:19:20Z Kris.Wallsmith $ + */ +class sfWidgetFormSelectUSState extends sfWidgetFormSelect +{ + /** + * @see sfWidget + */ + public function __construct($options = array(), $attributes = array()) + { + $options['choices'] = new sfCallable(array($this, 'getChoices')); + + parent::__construct($options, $attributes); + } + + /** + * @see sfWidget + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addOption('add_empty', false); + + parent::configure($options, $attributes); + } + + /** + * Returns choices for the current widget. + * + * @return array + */ + public function getChoices() + { + $choices = array(); + if (false !== $this->getOption('add_empty')) + { + $choices[''] = true === $this->getOption('add_empty') ? '' : $this->getOption('add_empty'); + } + + $choices = array_merge($choices, self::getStates()); + + return $choices; + } + + /** + * Returns an associative array of US states. + * + * @return array + */ + static public function getStates() + { + return self::$states; + } + + /** + * Sets the array of states. + * + * @param array $states + */ + static public function setStates(array $states) + { + self::$states = $states; + } + + /** + * Returns an array of state abbreviations. + * + * @return array + */ + static public function getStateAbbreviations() + { + return array_keys(self::$states); + } + + static protected $states = array( + 'AL' => 'Alabama', + 'AK' => 'Alaska', + 'AZ' => 'Arizona', + 'AR' => 'Arkansas', + 'CA' => 'California', + 'CO' => 'Colorado', + 'CT' => 'Connecticut', + 'DE' => 'Delaware', + 'DC' => 'District Of Columbia', + 'FL' => 'Florida', + 'GA' => 'Georgia', + 'HI' => 'Hawaii', + 'ID' => 'Idaho', + 'IL' => 'Illinois', + 'IN' => 'Indiana', + 'IA' => 'Iowa', + 'KS' => 'Kansas', + 'KY' => 'Kentucky', + 'LA' => 'Louisiana', + 'ME' => 'Maine', + 'MD' => 'Maryland', + 'MA' => 'Massachusetts', + 'MI' => 'Michigan', + 'MN' => 'Minnesota', + 'MS' => 'Mississippi', + 'MO' => 'Missouri', + 'MT' => 'Montana', + 'NE' => 'Nebraska', + 'NV' => 'Nevada', + 'NH' => 'New Hampshire', + 'NJ' => 'New Jersey', + 'NM' => 'New Mexico', + 'NY' => 'New York', + 'NC' => 'North Carolina', + 'ND' => 'North Dakota', + 'OH' => 'Ohio', + 'OK' => 'Oklahoma', + 'OR' => 'Oregon', + 'PA' => 'Pennsylvania', + 'RI' => 'Rhode Island', + 'SC' => 'South Carolina', + 'SD' => 'South Dakota', + 'TN' => 'Tennessee', + 'TX' => 'Texas', + 'UT' => 'Utah', + 'VT' => 'Vermont', + 'VA' => 'Virginia', + 'WA' => 'Washington', + 'WV' => 'West Virginia', + 'WI' => 'Wisconsin', + 'WY' => 'Wyoming', + ); +} diff --git a/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormTextareaTinyMCE.class.php b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormTextareaTinyMCE.class.php new file mode 100644 index 0000000..a3c67be --- /dev/null +++ b/plugins/sfFormExtraPlugin/lib/widget/sfWidgetFormTextareaTinyMCE.class.php @@ -0,0 +1,86 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +/** + * sfWidgetFormTextareaTinyMCE represents a Tiny MCE widget. + * + * You must include the Tiny MCE JavaScript file by yourself. + * + * @package symfony + * @subpackage widget + * @author Fabien Potencier + * @version SVN: $Id: sfWidgetFormTextareaTinyMCE.class.php 17192 2009-04-10 07:58:29Z fabien $ + */ +class sfWidgetFormTextareaTinyMCE extends sfWidgetFormTextarea +{ + /** + * Constructor. + * + * Available options: + * + * * theme: The Tiny MCE theme + * * width: Width + * * height: Height + * * config: The javascript configuration + * + * @param array $options An array of options + * @param array $attributes An array of default HTML attributes + * + * @see sfWidgetForm + */ + protected function configure($options = array(), $attributes = array()) + { + $this->addOption('theme', 'advanced'); + $this->addOption('width'); + $this->addOption('height'); + $this->addOption('config', ''); + } + + /** + * @param string $name The element name + * @param string $value The value selected in this widget + * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes + * @param array $errors An array of errors for the field + * + * @return string An HTML tag string + * + * @see sfWidgetForm + */ + public function render($name, $value = null, $attributes = array(), $errors = array()) + { + $textarea = parent::render($name, $value, $attributes, $errors); + + $js = sprintf(<< + tinyMCE.init({ + mode: "exact", + elements: "%s", + theme: "%s", + %s + %s + theme_advanced_toolbar_location: "top", + theme_advanced_toolbar_align: "left", + theme_advanced_statusbar_location: "bottom", + theme_advanced_resizing: true + %s + }); + +EOF + , + $this->generateId($name), + $this->getOption('theme'), + $this->getOption('width') ? sprintf('width: "%spx",', $this->getOption('width')) : '', + $this->getOption('height') ? sprintf('height: "%spx",', $this->getOption('height')) : '', + $this->getOption('config') ? ",\n".$this->getOption('config') : '' + ); + + return $textarea.$js; + } +} diff --git a/plugins/sfFormExtraPlugin/test/bootstrap.php b/plugins/sfFormExtraPlugin/test/bootstrap.php new file mode 100644 index 0000000..a8f1542 --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/bootstrap.php @@ -0,0 +1,18 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +if (!isset($_SERVER['SYMFONY'])) +{ + die("You must set the \"SYMFONY\" environment variable to the symfony lib dir (export SYMFONY=/path/to/symfony/lib/).\n"); +} + +require_once $_SERVER['SYMFONY'].'/vendor/lime/lime.php'; +require_once $_SERVER['SYMFONY'].'/autoload/sfCoreAutoload.class.php'; +sfCoreAutoload::register(); diff --git a/plugins/sfFormExtraPlugin/test/form/sfFormLanguageTest.php b/plugins/sfFormExtraPlugin/test/form/sfFormLanguageTest.php new file mode 100644 index 0000000..f3c3f4f --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/form/sfFormLanguageTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/form/sfFormLanguage.class.php'; + +$t = new lime_test(9, new lime_output_color()); + +// initialize objects +$dispatcher = new sfEventDispatcher(); + +$sessionPath = sys_get_temp_dir().'/sessions_'.rand(11111, 99999); +$storage = new sfSessionTestStorage(array('session_path' => $sessionPath)); +$user = new sfUser($dispatcher, $storage); +$user->setCulture('en'); + +$request = new sfWebRequest($dispatcher); + +// __construct() +$t->diag('__construct()'); +try +{ + new sfFormLanguage($user); + $t->fail('__construct() throws a RuntimeException if you don\'t pass a "languages" option'); +} +catch (RuntimeException $e) +{ + $t->pass('__construct() throws a RuntimeException if you don\'t pass a "languages" option'); +} +$form = new sfFormLanguage($user, array('languages' => array('en', 'fr'))); +$t->is($form->getDefault('language'), 'en', '__construct() sets the default language value to the user language'); +$w = $form->getWidgetSchema(); +$t->is($w['language']->getOption('languages'), array('en', 'fr'), '__construct() uses the "languages" option for the select form widget'); +$v = $form->getValidatorSchema(); +$t->is($v['language']->getOption('languages'), array('en', 'fr'), '__construct() uses the "languages" option for the validator'); + +// ->process() +$t->diag('->process()'); + +// with CSRF disabled +$t->diag('with CSRF disabled'); +sfForm::disableCSRFProtection(); + +$form = new sfFormLanguage($user, array('languages' => array('en', 'fr'))); +$request->setParameter('language', 'fr'); +$t->is($form->process($request), true, '->process() returns true if the form is valid'); +$t->is($user->getCulture(), 'fr', '->process() changes the user culture'); + +$request->setParameter('language', 'es'); +$t->is($form->process($request), false, '->process() returns true if the form is not valid'); +$t->is($form['language']->getError()->getCode(), 'invalid', '->process() throws an error if the language is not in the languages option'); + +sfToolkit::clearDirectory($sessionPath); + +// with CSRF enabled +$t->diag('with CSRF enabled'); +sfForm::enableCSRFProtection('secret'); + +$form = new sfFormLanguage($user, array('languages' => array('en', 'fr'))); +$request->setParameter('language', 'fr'); +$request->setParameter('_csrf_token', $form->getCSRFToken('secret')); +$t->is($form->process($request), true, '->process() returns true if the form is valid'); diff --git a/plugins/sfFormExtraPlugin/test/validator/sfValidatorBlacklistTest.php b/plugins/sfFormExtraPlugin/test/validator/sfValidatorBlacklistTest.php new file mode 100644 index 0000000..f95dd7c --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/validator/sfValidatorBlacklistTest.php @@ -0,0 +1,69 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/validator/sfValidatorBlacklist.class.php'; + +$t = new lime_test(6, new lime_output_color()); + +// __construct() +$t->diag('__construct()'); +try +{ + new sfValidatorBlacklist(); + $t->fail('__construct() expects a "forbidden_values" option'); +} +catch (RuntimeException $e) +{ + $t->pass('__construct() expects a "forbidden_values" option'); +} + +$v = new sfValidatorBlacklist(array('forbidden_values' => array('foo', 'bar', 'baz'))); + +// ->clean() +$t->diag('->clean()'); +try +{ + $v->clean('foo'); // "foo" is a forbidden value + $t->fail('->clean() throws a sfValidatorError when the submitted value is invalid'); + $t->skip(); +} +catch (sfValidatorError $e) +{ + $t->pass('->clean() throws a sfValidatorError when the submitted value is invalid'); + $t->is($e->getCode(), 'forbidden', '->clean() throws an "forbidden" error'); +} + +try +{ + $v->clean('gonzagues'); // "gonzagues" is not a forbidden value + $t->pass('->clean() does not throw a sfValidatorError when the submitted value is valid'); +} +catch (sfValidatorError $e) +{ + $t->fail('->clean() does not throw a sfValidatorError when the submitted value is valid'); +} + +$v = new sfValidatorBlacklist(array( + 'forbidden_values' => array('Foo', 'bAr', 'baZ'), + 'case_sensitive' => false, +)); + +try +{ + $v->clean('baz'); // "baz" is a forbidden value in a case sensitive context + $t->fail('->clean() throws a sfValidatorError when the submitted value is invalid in a case-insensitive context'); +} +catch (sfValidatorError $e) +{ + $t->pass('->clean() throws a sfValidatorError when the submitted value is invalid in a case-insensitive context'); +} + +$t->is($v->clean('FOOBAR'), 'FOOBAR', '->clean() does not change the value\'s case'); diff --git a/plugins/sfFormExtraPlugin/test/validator/sfValidatorDefaultTest.php b/plugins/sfFormExtraPlugin/test/validator/sfValidatorDefaultTest.php new file mode 100644 index 0000000..cf0e88c --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/validator/sfValidatorDefaultTest.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/validator/sfValidatorDefault.class.php'; + +$t = new lime_test(4); + +// ->clean() +$t->diag('->clean()'); + +$validator = new sfValidatorDefault(array( + 'validator' => new sfValidatorString(), + 'default' => '==DEFAULT==', +)); +$t->is($validator->clean('foo'), 'foo', '->clean() returns cleaned values'); +$t->is($validator->clean(null), '==DEFAULT==', '->clean() returns the default on validation failure'); + +$validator = new sfValidatorDefault(array( + 'validator' => new sfValidatorString(array('empty_value' => '==EMPTY==')), +)); +$t->is($validator->clean(null), '==EMPTY==', '->clean() returns the validator empty value if no default value is set'); + +$validator = new sfValidatorDefault(array( + 'validator' => new sfValidatorString(array('empty_value' => '==EMPTY==')), + 'default' => '==DEFAULT==', +)); +$t->is($validator->clean(null), '==DEFAULT==', '->clean() returns the default if both default and the embedded empty value are set'); diff --git a/plugins/sfFormExtraPlugin/test/validator/sfValidatorReCaptchaTest.php b/plugins/sfFormExtraPlugin/test/validator/sfValidatorReCaptchaTest.php new file mode 100644 index 0000000..d4cd07e --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/validator/sfValidatorReCaptchaTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/validator/sfValidatorReCaptcha.class.php'; + +$t = new lime_test(3, new lime_output_color()); + +$REMOTE_ADDR = 'symfony.example.com'; +$PUBLIC_KEY = '6Lf2DQEAAAAAALB9pGaVdcjMiv4CAuOVkfCSVvGh'; +$PRIVATE_KEY = '6Lf2DQEAAAAAALnEL0iEogIxZNYMlG7pmNhwEXjk'; + +// __construct() +$t->diag('__construct()'); +try +{ + new sfValidatorReCaptcha(); +} +catch (RuntimeException $e) +{ + $t->pass('__construct() expects a "private_key" option'); +} + +// ->clean() +$t->diag('->clean()'); +$v = new sfValidatorReCaptcha(array('private_key' => $PRIVATE_KEY, 'remote_addr' => $REMOTE_ADDR)); +try +{ + $v->clean(array( + 'recaptcha_challenge_field' => null, + 'recaptcha_response_field' => null, + 'captcha' => null, + )); + $t->fail('->clean() throws a sfValidatorError when the captcha is invalid'); + $t->skip(); +} +catch (sfValidatorError $e) +{ + $t->pass('->clean() throws a sfValidatorError when the captcha is invalid'); + $t->is($e->getCode(), 'captcha', '->clean() throws a captcha code'); +} diff --git a/plugins/sfFormExtraPlugin/test/validator/sfValidatorSchemaTimeIntervalTest.php b/plugins/sfFormExtraPlugin/test/validator/sfValidatorSchemaTimeIntervalTest.php new file mode 100644 index 0000000..1b7016c --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/validator/sfValidatorSchemaTimeIntervalTest.php @@ -0,0 +1,145 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/validator/sfValidatorSchemaTimeInterval.class.php'; + +$t = new lime_test(14, new lime_output_color()); + +// __construct() +$t->diag('__construct()'); +$v = new sfValidatorSchemaTimeInterval('start', 'end'); +$t->is($v->getOption('date_start_field'), 'start', '__construct() assigns date start field option'); +$t->is($v->getOption('date_end_field'), 'end', '__construct() assigns date end field option'); + +// clean() +$t->diag('clean()'); +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => false, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => null, 'end' => null)); + $t->pass('clean() validates if no dates are set'); +} +catch (sfValidatorErrorSchema $e) +{ + $t->fail('clean() validates if no dates are set'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => false, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => '2008-01-01', 'end' => '2007-01-01')); + $t->fail('clean() throws a sfValidatorError'); + $t->fail('clean() detects start date greater than end date'); +} +catch (sfValidatorErrorSchema $e) +{ + $t->isa_ok($e, 'sfValidatorErrorSchema', 'clean() throws a sfValidatorErrorSchema'); + $t->is($e->getCode(), 'start [start_not_prior]', 'clean() detects start date greater than end date'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => true, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => date('Y-m-d', time() + (365*24*3600)), 'end' => date('Y-m-d', time() + (366*24*3600)))); + $t->fail('clean() detects future date'); +} +catch (sfValidatorErrorSchema $e) +{ + $t->is($e->getCode(), 'start [future_date]', 'clean() detects future date'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_past_dates' => true, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => date('Y-m-d', time() - (365*24*3600)), 'end' => date('Y-m-d', time() - (366*24*3600)))); + $t->fail('clean() detects past date'); +} +catch (sfValidatorErrorSchema $e) +{ + $t->is($e->getCode(), 'start [past_date]', 'clean() detects past date'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => false, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => date('Y-m-d', time() + (365*24*3600)), 'end' => date('Y-m-d', time() + (366*24*3600)))); + $t->pass('clean() validates future dates if option allows it'); +} +catch (sfValidatorErrorSchema $e) +{ + $t->fail('clean() validates future dates if option allows it'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => false, 'throw_global_error' => true)); +try +{ + $v->clean(array('start' => '2008-01-01', 'end' => '2007-01-01')); + $t->fail('clean() throws a gobal error if option is set'); +} +catch (sfValidatorError $e) +{ + $t->isa_ok($e, 'sfValidatorError', 'clean() throws a gobal error if option is set'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => false, 'throw_global_error' => true)); +try +{ + $v->clean(array('start' => '2008-01-01', 'end' => null)); + $t->pass('clean() validates if end date is not set'); +} +catch (sfValidatorError $e) +{ + $t->fail('clean() validates if end date is not set'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('min_duration' => 86400 * 10, 'disallow_future_dates' => false, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => '2008-01-01', 'end' => '2008-01-09')); + $t->fail('clean() detects a too short duration'); +} +catch (sfValidatorError $e) +{ + $t->is($e->getCode(), 'end [too_short]', 'clean() detects a too short duration'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('max_duration' => 86400 * 10, 'disallow_future_dates' => false, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => '2008-01-01', 'end' => '2008-01-12')); + $t->fail('clean() detects an exceeded duration'); +} +catch (sfValidatorError $e) +{ + $t->is($e->getCode(), 'end [too_long]', 'clean() detects an exceeded duration'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_future_dates' => true, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => null, 'end' => date('Y-m-d', time() + (10*86400)))); + $t->fail('clean() detects an unique future date'); +} +catch (sfValidatorError $e) +{ + $t->pass('clean() detects an unique future date'); +} + +$v = new sfValidatorSchemaTimeInterval('start', 'end', array('disallow_past_dates' => true, 'throw_global_error' => false)); +try +{ + $v->clean(array('start' => null, 'end' => date('Y-m-d', time() - (10*86400)))); + $t->fail('clean() detects an unique past date'); +} +catch (sfValidatorError $e) +{ + $t->pass('clean() detects an unique past date'); +} \ No newline at end of file diff --git a/plugins/sfFormExtraPlugin/test/widget/sfWidgetFormReCaptchaTest.php b/plugins/sfFormExtraPlugin/test/widget/sfWidgetFormReCaptchaTest.php new file mode 100644 index 0000000..3cd5bd5 --- /dev/null +++ b/plugins/sfFormExtraPlugin/test/widget/sfWidgetFormReCaptchaTest.php @@ -0,0 +1,48 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +require_once dirname(__FILE__).'/../bootstrap.php'; +require_once dirname(__FILE__).'/../../lib/widget/sfWidgetFormReCaptcha.class.php'; +require_once $_SERVER['SYMFONY'].'/util/sfDomCssSelector.class.php'; + +$t = new lime_test(7, new lime_output_color()); + +$REMOTE_ADDR = 'symfony.example.com'; +$PUBLIC_KEY = '6Lf2DQEAAAAAALB9pGaVdcjMiv4CAuOVkfCSVvGh'; +$PRIVATE_KEY = '6Lf2DQEAAAAAALnEL0iEogIxZNYMlG7pmNhwEXjk'; + +// __construct() +$t->diag('__construct()'); +try +{ + new sfWidgetFormReCaptcha(); +} +catch (RuntimeException $e) +{ + $t->pass('__construct() expects a "public_key" option'); +} + +// ->render() +$t->diag('->render()'); +$w = new sfWidgetFormReCaptcha(array('public_key' => $PUBLIC_KEY)); +$dom = new DomDocument('1.0', 'utf-8'); +$dom->loadHTML($w->render('captcha')); +$c = new sfDomCssSelector($dom); +$t->is(count($c->matchSingle('script[src^="http://"]')->getNodes()), 1, '->render() uses the HTTP ReCaptcha URL by default'); +$t->is(count($c->matchSingle(sprintf('script[src$="%s"]', $PUBLIC_KEY))->getNodes()), 1, '->render() embeds the ReCatpcha public key in the URL'); +$t->is(count($c->matchSingle('iframe[src^="http://"]')->getNodes()), 1, '->render() uses the HTTP ReCaptcha URL by default'); +$t->is(count($c->matchSingle(sprintf('iframe[src$="%s"]', $PUBLIC_KEY))->getNodes()), 1, '->render() embeds the ReCatpcha public key in the URL'); + +$w = new sfWidgetFormReCaptcha(array('public_key' => $PUBLIC_KEY, 'use_ssl' => true)); +$dom = new DomDocument('1.0', 'utf-8'); +$dom->loadHTML($w->render('captcha')); +$c = new sfDomCssSelector($dom); +$t->is(count($c->matchSingle('script[src^="https://"]')->getNodes()), 1, '->render() uses the HTTPS ReCaptcha URL is use_ssl is true'); +$t->is(count($c->matchSingle('iframe[src^="https://"]')->getNodes()), 1, '->render() uses the HTTPS ReCaptcha URL is use_ssl is true'); diff --git a/plugins/sfFormExtraPlugin/web/css/jquery.autocompleter.css b/plugins/sfFormExtraPlugin/web/css/jquery.autocompleter.css new file mode 100644 index 0000000..4e6b634 --- /dev/null +++ b/plugins/sfFormExtraPlugin/web/css/jquery.autocompleter.css @@ -0,0 +1,48 @@ +.ac_results { + padding: 0px; + border: 1px solid black; + background-color: white; + overflow: hidden; + z-index: 99999; +} + +.ac_results ul { + width: 100%; + list-style-position: outside; + list-style: none; + padding: 0; + margin: 0; +} + +.ac_results li { + margin: 0px; + padding: 2px 5px; + cursor: default; + display: block; + /* + if width will be 100% horizontal scrollbar will apear + when scroll mode will be used + */ + /*width: 100%;*/ + font: menu; + font-size: 12px; + /* + it is very important, if line-height not setted or setted + in relative units scroll will be broken in firefox + */ + line-height: 16px; + overflow: hidden; +} + +.ac_loading { + background: white url('../images/indicator.gif') right center no-repeat; +} + +.ac_odd { + background-color: #eee; +} + +.ac_over { + background-color: #0A246A; + color: white; +} diff --git a/plugins/sfFormExtraPlugin/web/images/indicator.gif b/plugins/sfFormExtraPlugin/web/images/indicator.gif new file mode 100644 index 0000000..085ccae Binary files /dev/null and b/plugins/sfFormExtraPlugin/web/images/indicator.gif differ diff --git a/plugins/sfFormExtraPlugin/web/images/next.png b/plugins/sfFormExtraPlugin/web/images/next.png new file mode 100644 index 0000000..a1dafb9 Binary files /dev/null and b/plugins/sfFormExtraPlugin/web/images/next.png differ diff --git a/plugins/sfFormExtraPlugin/web/images/previous.png b/plugins/sfFormExtraPlugin/web/images/previous.png new file mode 100644 index 0000000..2a8890e Binary files /dev/null and b/plugins/sfFormExtraPlugin/web/images/previous.png differ diff --git a/plugins/sfFormExtraPlugin/web/js/double_list.js b/plugins/sfFormExtraPlugin/web/js/double_list.js new file mode 100644 index 0000000..7537a53 --- /dev/null +++ b/plugins/sfFormExtraPlugin/web/js/double_list.js @@ -0,0 +1,63 @@ +var sfDoubleList = +{ + init: function(id, className) + { + form = sfDoubleList.get_current_form(id); + + callback = function() { sfDoubleList.submit(form, className) }; + + if (form.addEventListener) + { + form.addEventListener("submit", callback, false); + } + else if (form.attachEvent) + { + var r = form.attachEvent("onsubmit", callback); + } + }, + + move: function(srcId, destId) + { + var src = document.getElementById(srcId); + var dest = document.getElementById(destId); + for (var i = 0; i < src.options.length; i++) + { + if (src.options[i].selected) + { + dest.options[dest.length] = new Option(src.options[i].text, src.options[i].value); + src.options[i] = null; + --i; + } + } + }, + + submit: function(form, className) + { + var element; + + for (var i = 0; i < form.elements.length; i++) + { + element = form.elements[i]; + if (element.type == 'select-multiple') + { + if (element.className == className + '-selected') + { + for (var j = 0; j < element.options.length; j++) + { + element.options[j].selected = true; + } + } + } + } + }, + + get_current_form: function(el) + { + if ("form" != el.tagName.toLowerCase()) + { + return sfDoubleList.get_current_form(el.parentNode); + } + + return el; + } +}; diff --git a/plugins/sfFormExtraPlugin/web/js/jquery.autocompleter.js b/plugins/sfFormExtraPlugin/web/js/jquery.autocompleter.js new file mode 100644 index 0000000..8387ba1 --- /dev/null +++ b/plugins/sfFormExtraPlugin/web/js/jquery.autocompleter.js @@ -0,0 +1,808 @@ +/* + * jQuery Autocomplete plugin 1.1 + * + * Copyright (c) 2009 Jörn Zaefferer + * + * Dual licensed under the MIT and GPL licenses: + * http://www.opensource.org/licenses/mit-license.php + * http://www.gnu.org/licenses/gpl.html + * + * Revision: $Id: jquery.autocomplete.js 15 2009-08-22 10:30:27Z joern.zaefferer $ + */ + +;(function($) { + +$.fn.extend({ + autocomplete: function(urlOrData, options) { + var isUrl = typeof urlOrData == "string"; + options = $.extend({}, $.Autocompleter.defaults, { + url: isUrl ? urlOrData : null, + data: isUrl ? null : urlOrData, + delay: isUrl ? $.Autocompleter.defaults.delay : 10, + max: options && !options.scroll ? 10 : 150 + }, options); + + // if highlight is set to false, replace it with a do-nothing function + options.highlight = options.highlight || function(value) { return value; }; + + // if the formatMatch option is not specified, then use formatItem for backwards compatibility + options.formatMatch = options.formatMatch || options.formatItem; + + return this.each(function() { + new $.Autocompleter(this, options); + }); + }, + result: function(handler) { + return this.bind("result", handler); + }, + search: function(handler) { + return this.trigger("search", [handler]); + }, + flushCache: function() { + return this.trigger("flushCache"); + }, + setOptions: function(options){ + return this.trigger("setOptions", [options]); + }, + unautocomplete: function() { + return this.trigger("unautocomplete"); + } +}); + +$.Autocompleter = function(input, options) { + + var KEY = { + UP: 38, + DOWN: 40, + DEL: 46, + TAB: 9, + RETURN: 13, + ESC: 27, + COMMA: 188, + PAGEUP: 33, + PAGEDOWN: 34, + BACKSPACE: 8 + }; + + // Create $ object for input element + var $input = $(input).attr("autocomplete", "off").addClass(options.inputClass); + + var timeout; + var previousValue = ""; + var cache = $.Autocompleter.Cache(options); + var hasFocus = 0; + var lastKeyPressCode; + var config = { + mouseDownOnSelect: false + }; + var select = $.Autocompleter.Select(options, input, selectCurrent, config); + + var blockSubmit; + + // prevent form submit in opera when selecting with return key + $.browser.opera && $(input.form).bind("submit.autocomplete", function() { + if (blockSubmit) { + blockSubmit = false; + return false; + } + }); + + // only opera doesn't trigger keydown multiple times while pressed, others don't work with keypress at all + $input.bind(($.browser.opera ? "keypress" : "keydown") + ".autocomplete", function(event) { + // a keypress means the input has focus + // avoids issue where input had focus before the autocomplete was applied + hasFocus = 1; + // track last key pressed + lastKeyPressCode = event.keyCode; + switch(event.keyCode) { + + case KEY.UP: + event.preventDefault(); + if ( select.visible() ) { + select.prev(); + } else { + onChange(0, true); + } + break; + + case KEY.DOWN: + event.preventDefault(); + if ( select.visible() ) { + select.next(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEUP: + event.preventDefault(); + if ( select.visible() ) { + select.pageUp(); + } else { + onChange(0, true); + } + break; + + case KEY.PAGEDOWN: + event.preventDefault(); + if ( select.visible() ) { + select.pageDown(); + } else { + onChange(0, true); + } + break; + + // matches also semicolon + case options.multiple && $.trim(options.multipleSeparator) == "," && KEY.COMMA: + case KEY.TAB: + case KEY.RETURN: + if( selectCurrent() ) { + // stop default to prevent a form submit, Opera needs special handling + event.preventDefault(); + blockSubmit = true; + return false; + } + break; + + case KEY.ESC: + select.hide(); + break; + + default: + clearTimeout(timeout); + timeout = setTimeout(onChange, options.delay); + break; + } + }).focus(function(){ + // track whether the field has focus, we shouldn't process any + // results if the field no longer has focus + hasFocus++; + }).blur(function() { + hasFocus = 0; + if (!config.mouseDownOnSelect) { + hideResults(); + } + }).click(function() { + // show select when clicking in a focused field + if ( hasFocus++ > 1 && !select.visible() ) { + onChange(0, true); + } + }).bind("search", function() { + // TODO why not just specifying both arguments? + var fn = (arguments.length > 1) ? arguments[1] : null; + function findValueCallback(q, data) { + var result; + if( data && data.length ) { + for (var i=0; i < data.length; i++) { + if( data[i].result.toLowerCase() == q.toLowerCase() ) { + result = data[i]; + break; + } + } + } + if( typeof fn == "function" ) fn(result); + else $input.trigger("result", result && [result.data, result.value]); + } + $.each(trimWords($input.val()), function(i, value) { + request(value, findValueCallback, findValueCallback); + }); + }).bind("flushCache", function() { + cache.flush(); + }).bind("setOptions", function() { + $.extend(options, arguments[1]); + // if we've updated the data, repopulate + if ( "data" in arguments[1] ) + cache.populate(); + }).bind("unautocomplete", function() { + select.unbind(); + $input.unbind(); + $(input.form).unbind(".autocomplete"); + }); + + + function selectCurrent() { + var selected = select.selected(); + if( !selected ) + return false; + + var v = selected.result; + previousValue = v; + + if ( options.multiple ) { + var words = trimWords($input.val()); + if ( words.length > 1 ) { + var seperator = options.multipleSeparator.length; + var cursorAt = $(input).selection().start; + var wordAt, progress = 0; + $.each(words, function(i, word) { + progress += word.length; + if (cursorAt <= progress) { + wordAt = i; + return false; + } + progress += seperator; + }); + words[wordAt] = v; + // TODO this should set the cursor to the right position, but it gets overriden somewhere + //$.Autocompleter.Selection(input, progress + seperator, progress + seperator); + v = words.join( options.multipleSeparator ); + } + v += options.multipleSeparator; + } + + $input.val(v); + hideResultsNow(); + $input.trigger("result", [selected.data, selected.value]); + return true; + } + + function onChange(crap, skipPrevCheck) { + if( lastKeyPressCode == KEY.DEL ) { + select.hide(); + return; + } + + var currentValue = $input.val(); + + if ( !skipPrevCheck && currentValue == previousValue ) + return; + + previousValue = currentValue; + + currentValue = lastWord(currentValue); + if ( currentValue.length >= options.minChars) { + $input.addClass(options.loadingClass); + if (!options.matchCase) + currentValue = currentValue.toLowerCase(); + request(currentValue, receiveData, hideResultsNow); + } else { + stopLoading(); + select.hide(); + } + }; + + function trimWords(value) { + if (!value) + return [""]; + if (!options.multiple) + return [$.trim(value)]; + return $.map(value.split(options.multipleSeparator), function(word) { + return $.trim(value).length ? $.trim(word) : null; + }); + } + + function lastWord(value) { + if ( !options.multiple ) + return value; + var words = trimWords(value); + if (words.length == 1) + return words[0]; + var cursorAt = $(input).selection().start; + if (cursorAt == value.length) { + words = trimWords(value) + } else { + words = trimWords(value.replace(value.substring(cursorAt), "")); + } + return words[words.length - 1]; + } + + // fills in the input box w/the first match (assumed to be the best match) + // q: the term entered + // sValue: the first matching result + function autoFill(q, sValue){ + // autofill in the complete box w/the first match as long as the user hasn't entered in more data + // if the last user key pressed was backspace, don't autofill + if( options.autoFill && (lastWord($input.val()).toLowerCase() == q.toLowerCase()) && lastKeyPressCode != KEY.BACKSPACE ) { + // fill in the value (keep the case the user has typed) + $input.val($input.val() + sValue.substring(lastWord(previousValue).length)); + // select the portion of the value not typed by the user (so the next character will erase) + $(input).selection(previousValue.length, previousValue.length + sValue.length); + } + }; + + function hideResults() { + clearTimeout(timeout); + timeout = setTimeout(hideResultsNow, 200); + }; + + function hideResultsNow() { + var wasVisible = select.visible(); + select.hide(); + clearTimeout(timeout); + stopLoading(); + if (options.mustMatch) { + // call search and run callback + $input.search( + function (result){ + // if no value found, clear the input box + if( !result ) { + if (options.multiple) { + var words = trimWords($input.val()).slice(0, -1); + $input.val( words.join(options.multipleSeparator) + (words.length ? options.multipleSeparator : "") ); + } + else { + $input.val( "" ); + $input.trigger("result", null); + } + } + } + ); + } + }; + + function receiveData(q, data) { + if ( data && data.length && hasFocus ) { + stopLoading(); + select.display(data, q); + autoFill(q, data[0].value); + select.show(); + } else { + hideResultsNow(); + } + }; + + function request(term, success, failure) { + if (!options.matchCase) + term = term.toLowerCase(); + var data = cache.load(term); + // recieve the cached data + if (data && data.length) { + success(term, data); + // if an AJAX url has been supplied, try loading the data now + } else if( (typeof options.url == "string") && (options.url.length > 0) ){ + + var extraParams = { + timestamp: +new Date() + }; + $.each(options.extraParams, function(key, param) { + extraParams[key] = typeof param == "function" ? param() : param; + }); + + $.ajax({ + // try to leverage ajaxQueue plugin to abort previous requests + mode: "abort", + // limit abortion to this input + port: "autocomplete" + input.name, + dataType: options.dataType, + url: options.url, + data: $.extend({ + q: lastWord(term), + limit: options.max + }, extraParams), + success: function(data) { + var parsed = options.parse && options.parse(data) || parse(data); + cache.add(term, parsed); + success(term, parsed); + } + }); + } else { + // if we have a failure, we need to empty the list -- this prevents the the [TAB] key from selecting the last successful match + select.emptyList(); + failure(term); + } + }; + + function parse(data) { + var parsed = []; + var rows = data.split("\n"); + for (var i=0; i < rows.length; i++) { + var row = $.trim(rows[i]); + if (row) { + row = row.split("|"); + parsed[parsed.length] = { + data: row, + value: row[0], + result: options.formatResult && options.formatResult(row, row[0]) || row[0] + }; + } + } + return parsed; + }; + + function stopLoading() { + $input.removeClass(options.loadingClass); + }; + +}; + +$.Autocompleter.defaults = { + inputClass: "ac_input", + resultsClass: "ac_results", + loadingClass: "ac_loading", + minChars: 1, + delay: 400, + matchCase: false, + matchSubset: true, + matchContains: false, + cacheLength: 10, + max: 100, + mustMatch: false, + extraParams: {}, + selectFirst: true, + formatItem: function(row) { return row[0]; }, + formatMatch: null, + autoFill: false, + width: 0, + multiple: false, + multipleSeparator: ", ", + highlight: function(value, term) { + return value.replace(new RegExp("(?![^&;]+;)(?!<[^<>]*)(" + term.replace(/([\^\$\(\)\[\]\{\}\*\.\+\?\|\\])/gi, "\\$1") + ")(?![^<>]*>)(?![^&;]+;)", "gi"), "$1"); + }, + scroll: true, + scrollHeight: 180 +}; + +$.Autocompleter.Cache = function(options) { + + var data = {}; + var length = 0; + + function matchSubset(s, sub) { + if (!options.matchCase) + s = s.toLowerCase(); + var i = s.indexOf(sub); + if (options.matchContains == "word"){ + i = s.toLowerCase().search("\\b" + sub.toLowerCase()); + } + if (i == -1) return false; + return i == 0 || options.matchContains; + }; + + function add(q, value) { + if (length > options.cacheLength){ + flush(); + } + if (!data[q]){ + length++; + } + data[q] = value; + } + + function populate(){ + if( !options.data ) return false; + // track the matches + var stMatchSets = {}, + nullData = 0; + + // no url was specified, we need to adjust the cache length to make sure it fits the local data store + if( !options.url ) options.cacheLength = 1; + + // track all options for minChars = 0 + stMatchSets[""] = []; + + // loop through the array and create a lookup structure + for ( var i = 0, ol = options.data.length; i < ol; i++ ) { + var rawValue = options.data[i]; + // if rawValue is a string, make an array otherwise just reference the array + rawValue = (typeof rawValue == "string") ? [rawValue] : rawValue; + + var value = options.formatMatch(rawValue, i+1, options.data.length); + if ( value === false ) + continue; + + var firstChar = value.charAt(0).toLowerCase(); + // if no lookup array for this character exists, look it up now + if( !stMatchSets[firstChar] ) + stMatchSets[firstChar] = []; + + // if the match is a string + var row = { + value: value, + data: rawValue, + result: options.formatResult && options.formatResult(rawValue) || value + }; + + // push the current match into the set list + stMatchSets[firstChar].push(row); + + // keep track of minChars zero items + if ( nullData++ < options.max ) { + stMatchSets[""].push(row); + } + }; + + // add the data items to the cache + $.each(stMatchSets, function(i, value) { + // increase the cache size + options.cacheLength++; + // add to the cache + add(i, value); + }); + } + + // populate any existing data + setTimeout(populate, 25); + + function flush(){ + data = {}; + length = 0; + } + + return { + flush: flush, + add: add, + populate: populate, + load: function(q) { + if (!options.cacheLength || !length) + return null; + /* + * if dealing w/local data and matchContains than we must make sure + * to loop through all the data collections looking for matches + */ + if( !options.url && options.matchContains ){ + // track all matches + var csub = []; + // loop through all the data grids for matches + for( var k in data ){ + // don't search through the stMatchSets[""] (minChars: 0) cache + // this prevents duplicates + if( k.length > 0 ){ + var c = data[k]; + $.each(c, function(i, x) { + // if we've got a match, add it to the array + if (matchSubset(x.value, q)) { + csub.push(x); + } + }); + } + } + return csub; + } else + // if the exact item exists, use it + if (data[q]){ + return data[q]; + } else + if (options.matchSubset) { + for (var i = q.length - 1; i >= options.minChars; i--) { + var c = data[q.substr(0, i)]; + if (c) { + var csub = []; + $.each(c, function(i, x) { + if (matchSubset(x.value, q)) { + csub[csub.length] = x; + } + }); + return csub; + } + } + } + return null; + } + }; +}; + +$.Autocompleter.Select = function (options, input, select, config) { + var CLASSES = { + ACTIVE: "ac_over" + }; + + var listItems, + active = -1, + data, + term = "", + needsInit = true, + element, + list; + + // Create results + function init() { + if (!needsInit) + return; + element = $("
") + .hide() + .addClass(options.resultsClass) + .css("position", "absolute") + .appendTo(document.body); + + list = $("
    ").appendTo(element).mouseover( function(event) { + if(target(event).nodeName && target(event).nodeName.toUpperCase() == 'LI') { + active = $("li", list).removeClass(CLASSES.ACTIVE).index(target(event)); + $(target(event)).addClass(CLASSES.ACTIVE); + } + }).click(function(event) { + $(target(event)).addClass(CLASSES.ACTIVE); + select(); + // TODO provide option to avoid setting focus again after selection? useful for cleanup-on-focus + input.focus(); + return false; + }).mousedown(function() { + config.mouseDownOnSelect = true; + }).mouseup(function() { + config.mouseDownOnSelect = false; + }); + + if( options.width > 0 ) + element.css("width", options.width); + + needsInit = false; + } + + function target(event) { + var element = event.target; + while(element && element.tagName != "LI") + element = element.parentNode; + // more fun with IE, sometimes event.target is empty, just ignore it then + if(!element) + return []; + return element; + } + + function moveSelect(step) { + listItems.slice(active, active + 1).removeClass(CLASSES.ACTIVE); + movePosition(step); + var activeItem = listItems.slice(active, active + 1).addClass(CLASSES.ACTIVE); + if(options.scroll) { + var offset = 0; + listItems.slice(0, active).each(function() { + offset += this.offsetHeight; + }); + if((offset + activeItem[0].offsetHeight - list.scrollTop()) > list[0].clientHeight) { + list.scrollTop(offset + activeItem[0].offsetHeight - list.innerHeight()); + } else if(offset < list.scrollTop()) { + list.scrollTop(offset); + } + } + }; + + function movePosition(step) { + active += step; + if (active < 0) { + active = listItems.size() - 1; + } else if (active >= listItems.size()) { + active = 0; + } + } + + function limitNumberOfItems(available) { + return options.max && options.max < available + ? options.max + : available; + } + + function fillList() { + list.empty(); + var max = limitNumberOfItems(data.length); + for (var i=0; i < max; i++) { + if (!data[i]) + continue; + var formatted = options.formatItem(data[i].data, i+1, max, data[i].value, term); + if ( formatted === false ) + continue; + var li = $("
  • ").html( options.highlight(formatted, term) ).addClass(i%2 == 0 ? "ac_even" : "ac_odd").appendTo(list)[0]; + $.data(li, "ac_data", data[i]); + } + listItems = list.find("li"); + if ( options.selectFirst ) { + listItems.slice(0, 1).addClass(CLASSES.ACTIVE); + active = 0; + } + // apply bgiframe if available + if ( $.fn.bgiframe ) + list.bgiframe(); + } + + return { + display: function(d, q) { + init(); + data = d; + term = q; + fillList(); + }, + next: function() { + moveSelect(1); + }, + prev: function() { + moveSelect(-1); + }, + pageUp: function() { + if (active != 0 && active - 8 < 0) { + moveSelect( -active ); + } else { + moveSelect(-8); + } + }, + pageDown: function() { + if (active != listItems.size() - 1 && active + 8 > listItems.size()) { + moveSelect( listItems.size() - 1 - active ); + } else { + moveSelect(8); + } + }, + hide: function() { + element && element.hide(); + listItems && listItems.removeClass(CLASSES.ACTIVE); + active = -1; + }, + visible : function() { + return element && element.is(":visible"); + }, + current: function() { + return this.visible() && (listItems.filter("." + CLASSES.ACTIVE)[0] || options.selectFirst && listItems[0]); + }, + show: function() { + var offset = $(input).offset(); + element.css({ + width: typeof options.width == "string" || options.width > 0 ? options.width : $(input).width(), + top: offset.top + input.offsetHeight, + left: offset.left + }).show(); + if(options.scroll) { + list.scrollTop(0); + list.css({ + maxHeight: options.scrollHeight, + overflow: 'auto' + }); + + if($.browser.msie && typeof document.body.style.maxHeight === "undefined") { + var listHeight = 0; + listItems.each(function() { + listHeight += this.offsetHeight; + }); + var scrollbarsVisible = listHeight > options.scrollHeight; + list.css('height', scrollbarsVisible ? options.scrollHeight : listHeight ); + if (!scrollbarsVisible) { + // IE doesn't recalculate width when scrollbar disappears + listItems.width( list.width() - parseInt(listItems.css("padding-left")) - parseInt(listItems.css("padding-right")) ); + } + } + + } + }, + selected: function() { + var selected = listItems && listItems.filter("." + CLASSES.ACTIVE).removeClass(CLASSES.ACTIVE); + return selected && selected.length && $.data(selected[0], "ac_data"); + }, + emptyList: function (){ + list && list.empty(); + }, + unbind: function() { + element && element.remove(); + } + }; +}; + +$.fn.selection = function(start, end) { + if (start !== undefined) { + return this.each(function() { + if( this.createTextRange ){ + var selRange = this.createTextRange(); + if (end === undefined || start == end) { + selRange.move("character", start); + selRange.select(); + } else { + selRange.collapse(true); + selRange.moveStart("character", start); + selRange.moveEnd("character", end); + selRange.select(); + } + } else if( this.setSelectionRange ){ + this.setSelectionRange(start, end); + } else if( this.selectionStart ){ + this.selectionStart = start; + this.selectionEnd = end; + } + }); + } + var field = this[0]; + if ( field.createTextRange ) { + var range = document.selection.createRange(), + orig = field.value, + teststring = "<->", + textLength = range.text.length; + range.text = teststring; + var caretAt = field.value.indexOf(teststring); + field.value = orig; + this.selection(caretAt, caretAt + textLength); + return { + start: caretAt, + end: caretAt + textLength + } + } else if( field.selectionStart !== undefined ){ + return { + start: field.selectionStart, + end: field.selectionEnd + } + } +}; + +})(jQuery);