diff --git a/config/services.config.php b/config/services.config.php index 7f6009b..20c2e58 100644 --- a/config/services.config.php +++ b/config/services.config.php @@ -4,96 +4,16 @@ * Date: 3/18/13 * Time: 6:39 PM */ -use Zend\ServiceManager\ServiceLocatorInterface; -use ZfcUser\Form\RegisterFilter; -use ZfcUser\Mapper\UserHydrator; -use ZfcUser\Validator\NoRecordExists; -use ZfcUserAdmin\Form; -use ZfcUserAdmin\Options; -use ZfcUserAdmin\Validator\NoRecordExistsEdit; return array( 'invokables' => array( - 'ZfcUserAdmin\Form\EditUser' => 'ZfcUserAdmin\Form\EditUser', - 'zfcuseradmin_user_service' => 'ZfcUserAdmin\Service\User', + 'ZfcUserAdmin\Form\EditUser' => 'ZfcUserAdmin\Form\EditUser', + 'zfcuseradmin_user_service' => 'ZfcUserAdmin\Service\User', ), 'factories' => array( - 'zfcuseradmin_module_options' => function (ServiceLocatorInterface $sm) { - $config = $sm->get('Config'); - return new Options\ModuleOptions(isset($config['zfcuseradmin']) ? $config['zfcuseradmin'] : array()); - }, - 'zfcuseradmin_edituser_form' => function (ServiceLocatorInterface $sm) { - /** @var $zfcUserOptions \ZfcUser\Options\UserServiceOptionsInterface */ - $zfcUserOptions = $sm->get('zfcuser_module_options'); - /** @var $zfcUserAdminOptions \ZfcUserAdmin\Options\ModuleOptions */ - $zfcUserAdminOptions = $sm->get('zfcuseradmin_module_options'); - $form = new Form\EditUser(null, $zfcUserAdminOptions, $zfcUserOptions, $sm); - $filter = new RegisterFilter( - new NoRecordExistsEdit(array( - 'mapper' => $sm->get('zfcuser_user_mapper'), - 'key' => 'email' - )), - new NoRecordExistsEdit(array( - 'mapper' => $sm->get('zfcuser_user_mapper'), - 'key' => 'username' - )), - $zfcUserOptions - ); - if (!$zfcUserAdminOptions->getAllowPasswordChange()) { - $filter->remove('password')->remove('passwordVerify'); - } else { - $filter->get('password')->setRequired(false); - $filter->remove('passwordVerify'); - } - $form->setInputFilter($filter); - return $form; - }, - 'zfcuseradmin_createuser_form' => function (ServiceLocatorInterface $sm) { - /** @var $zfcUserOptions \ZfcUser\Options\UserServiceOptionsInterface */ - $zfcUserOptions = $sm->get('zfcuser_module_options'); - /** @var $zfcUserAdminOptions \ZfcUserAdmin\Options\ModuleOptions */ - $zfcUserAdminOptions = $sm->get('zfcuseradmin_module_options'); - $form = new Form\CreateUser(null, $zfcUserAdminOptions, $zfcUserOptions, $sm); - $filter = new RegisterFilter( - new NoRecordExists(array( - 'mapper' => $sm->get('zfcuser_user_mapper'), - 'key' => 'email' - )), - new NoRecordExists(array( - 'mapper' => $sm->get('zfcuser_user_mapper'), - 'key' => 'username' - )), - $zfcUserOptions - ); - if ($zfcUserAdminOptions->getCreateUserAutoPassword()) { - $filter->remove('password')->remove('passwordVerify'); - } - $form->setInputFilter($filter); - return $form; - }, - 'zfcuser_user_mapper' => function (ServiceLocatorInterface $sm) { - /** @var $config \ZfcUserAdmin\Options\ModuleOptions */ - $config = $sm->get('zfcuseradmin_module_options'); - $mapperClass = $config->getUserMapper(); - if (stripos($mapperClass, 'doctrine') !== false) { - $mapper = new $mapperClass( - $sm->get('zfcuser_doctrine_em'), - $sm->get('zfcuser_module_options') - ); - } else { - /** @var $zfcUserOptions \ZfcUser\Options\UserServiceOptionsInterface */ - $zfcUserOptions = $sm->get('zfcuser_module_options'); - - /** @var $mapper \ZfcUserAdmin\Mapper\UserZendDb */ - $mapper = new $mapperClass(); - $mapper->setDbAdapter($sm->get('zfcuser_zend_db_adapter')); - $entityClass = $zfcUserOptions->getUserEntityClass(); - $mapper->setEntityPrototype(new $entityClass); - $mapper->setHydrator($sm->get('zfcuser_user_hydrator')); - $mapper->setTableName($zfcUserOptions->getTableName()); - } - - return $mapper; - }, + 'zfcuseradmin_module_options' => 'ZfcUserAdmin\Factory\Options\ModuleOptionsFactory', + 'zfcuser_user_mapper' => 'ZfcUserAdmin\Factory\Mapper\UserZendDbFactory', + 'zfcuseradmin_createuser_form' => 'ZfcUserAdmin\Factory\Form\CreateUserFactory', + 'zfcuseradmin_edituser_form' => 'ZfcUserAdmin\Factory\Form\EditUserFactory', ), ); diff --git a/src/ZfcUserAdmin/Controller/UserAdminController.php b/src/ZfcUserAdmin/Controller/UserAdminController.php index 4671f0b..3d99814 100644 --- a/src/ZfcUserAdmin/Controller/UserAdminController.php +++ b/src/ZfcUserAdmin/Controller/UserAdminController.php @@ -40,19 +40,19 @@ public function createAction() { /** @var $form \ZfcUserAdmin\Form\CreateUser */ $form = $this->getServiceLocator()->get('zfcuseradmin_createuser_form'); + /** @var $request \Zend\Http\Request */ $request = $this->getRequest(); - /** @var $request \Zend\Http\Request */ if ($request->isPost()) { $zfcUserOptions = $this->getZfcUserOptions(); $class = $zfcUserOptions->getUserEntityClass(); $user = new $class(); - $form->setHydrator(new ClassMethods()); $form->bind($user); + $form->setData($request->getPost()); if ($form->isValid()) { - $user = $this->getAdminUserService()->create($form, (array)$request->getPost()); + $user = $this->getAdminUserService()->create($form, (array)$request->getPost(), $user); if ($user) { $this->flashMessenger()->addSuccessMessage('The user was created'); return $this->redirect()->toRoute('zfcadmin/zfcuseradmin/list'); @@ -67,15 +67,17 @@ public function createAction() public function editAction() { - $userId = $this->getEvent()->getRouteMatch()->getParam('userId'); - $user = $this->getUserMapper()->findById($userId); - /** @var $form \ZfcUserAdmin\Form\EditUser */ $form = $this->getServiceLocator()->get('zfcuseradmin_edituser_form'); - $form->setUser($user); - /** @var $request \Zend\Http\Request */ $request = $this->getRequest(); + + $userId = $this->getEvent()->getRouteMatch()->getParam('userId'); + $user = $this->getUserMapper()->findById($userId); + $form->bind($user); + + // don't automatically overwrite password since input permit blank + $form->getInputFilter()->remove('password'); if ($request->isPost()) { $form->setData($request->getPost()); if ($form->isValid()) { @@ -85,9 +87,10 @@ public function editAction() return $this->redirect()->toRoute('zfcadmin/zfcuseradmin/list'); } } - } else { - $form->populateFromUser($user); } + // Necessary so validators know whether a username and email have changed since they may be a "duplicate" of + // their own database record, but not of other users. + $form->get('userId')->setValue($user->getId()); return array( 'editUserForm' => $form, diff --git a/src/ZfcUserAdmin/Factory/Form/CreateUserFactory.php b/src/ZfcUserAdmin/Factory/Form/CreateUserFactory.php new file mode 100644 index 0000000..ef37ef8 --- /dev/null +++ b/src/ZfcUserAdmin/Factory/Form/CreateUserFactory.php @@ -0,0 +1,42 @@ +get('zfcuser_module_options'); + /** @var $zfcUserAdminOptions \ZfcUserAdmin\Options\ModuleOptions */ + $zfcUserAdminOptions = $serviceLocator->get('zfcuseradmin_module_options'); + $form = new CreateUser(null, $zfcUserAdminOptions, $zfcUserOptions, $serviceLocator); + $filter = new RegisterFilter( + new NoRecordExists(array( + 'mapper' => $serviceLocator->get('zfcuser_user_mapper'), + 'key' => 'email' + )), + new NoRecordExists(array( + 'mapper' => $serviceLocator->get('zfcuser_user_mapper'), + 'key' => 'username' + )), + $zfcUserOptions + ); + if ($zfcUserAdminOptions->getCreateUserAutoPassword()) { + $filter->remove('password')->remove('passwordVerify'); + } + $form->setInputFilter($filter); + return $form; + } +} \ No newline at end of file diff --git a/src/ZfcUserAdmin/Factory/Form/EditUserFactory.php b/src/ZfcUserAdmin/Factory/Form/EditUserFactory.php new file mode 100644 index 0000000..32f9226 --- /dev/null +++ b/src/ZfcUserAdmin/Factory/Form/EditUserFactory.php @@ -0,0 +1,45 @@ +get('zfcuser_module_options'); + /** @var $zfcUserAdminOptions \ZfcUserAdmin\Options\ModuleOptions */ + $zfcUserAdminOptions = $serviceLocator->get('zfcuseradmin_module_options'); + $form = new EditUser(null, $zfcUserAdminOptions, $zfcUserOptions, $serviceLocator); + $filter = new RegisterFilter( + new NoRecordExistsEdit(array( + 'mapper' => $serviceLocator->get('zfcuser_user_mapper'), + 'key' => 'email' + )), + new NoRecordExistsEdit(array( + 'mapper' => $serviceLocator->get('zfcuser_user_mapper'), + 'key' => 'username' + )), + $zfcUserOptions + ); + if (!$zfcUserAdminOptions->getAllowPasswordChange()) { + $filter->remove('password')->remove('passwordVerify'); + } else { + $filter->get('password')->setRequired(false); + $filter->remove('passwordVerify'); + } + $form->setInputFilter($filter); + return $form; + } +} \ No newline at end of file diff --git a/src/ZfcUserAdmin/Factory/Mapper/UserZendDbFactory.php b/src/ZfcUserAdmin/Factory/Mapper/UserZendDbFactory.php new file mode 100644 index 0000000..74440da --- /dev/null +++ b/src/ZfcUserAdmin/Factory/Mapper/UserZendDbFactory.php @@ -0,0 +1,40 @@ +get('zfcuseradmin_module_options'); + $mapperClass = $config->getUserMapper(); + if (stripos($mapperClass, 'doctrine') !== false) { + $mapper = new $mapperClass( + $serviceLocator->get('zfcuser_doctrine_em'), + $serviceLocator->get('zfcuser_module_options') + ); + } else { + /** @var $zfcUserOptions \ZfcUser\Options\UserServiceOptionsInterface */ + $zfcUserOptions = $serviceLocator->get('zfcuser_module_options'); + + /** @var $mapper \ZfcUserAdmin\Mapper\UserZendDb */ + $mapper = new $mapperClass(); + $mapper->setDbAdapter($serviceLocator->get('zfcuser_zend_db_adapter')); + $entityClass = $zfcUserOptions->getUserEntityClass(); + $mapper->setEntityPrototype(new $entityClass); + $mapper->setHydrator($serviceLocator->get('zfcuser_user_hydrator')); + $mapper->setTableName($zfcUserOptions->getTableName()); + } + + return $mapper; + } +} \ No newline at end of file diff --git a/src/ZfcUserAdmin/Factory/Options/ModuleOptionsFactory.php b/src/ZfcUserAdmin/Factory/Options/ModuleOptionsFactory.php new file mode 100644 index 0000000..45d4829 --- /dev/null +++ b/src/ZfcUserAdmin/Factory/Options/ModuleOptionsFactory.php @@ -0,0 +1,21 @@ +get('Config'); + return new ModuleOptions(isset($config['zfcuseradmin']) ? $config['zfcuseradmin'] : array()); + } +} \ No newline at end of file diff --git a/src/ZfcUserAdmin/Form/CreateUser.php b/src/ZfcUserAdmin/Form/CreateUser.php index cd3d95d..6c0dd16 100644 --- a/src/ZfcUserAdmin/Form/CreateUser.php +++ b/src/ZfcUserAdmin/Form/CreateUser.php @@ -2,9 +2,10 @@ namespace ZfcUserAdmin\Form; -use ZfcUserAdmin\Options\UserCreateOptionsInterface; +use Zend\Stdlib\Hydrator\ClassMethods; use ZfcUser\Options\RegistrationOptionsInterface; use ZfcUser\Form\Register as Register; +use ZfcUserAdmin\Options\UserCreateOptionsInterface; class CreateUser extends Register { @@ -24,6 +25,8 @@ public function __construct($name = null, UserCreateOptionsInterface $createOpti $this->setCreateOptions($createOptions); $this->setServiceManager($serviceManager); parent::__construct($name, $registerOptions); + // ZfcUser should have setHydrator() which we replace or extend + $this->setHydrator($serviceManager->get('zfcuser_user_hydrator')); if ($createOptions->getCreateUserAutoPassword()) { $this->remove('password'); @@ -68,4 +71,34 @@ public function getServiceManager() { return $this->serviceManager; } + + /** + * Override isValid() to set an validation group of all elements that do not + * have an 'exclude' option, if at least one element has this option set. + * + * @return boolean + */ + public function isValid() + { + if ($this->hasValidated) { + return $this->isValid; + } + + if ($this->getValidationGroup() === null) { + // Add all non-excluded elements to the validation group + $validationGroup = null; + foreach ($this->getElements() as $element) { + if ($element->getOption('exclude') === false or + ($element->getAttribute('readonly') !== true && $element->getOption('exclude') !== true)) + { + $validationGroup[] = $element->getName(); + } + } + if ($validationGroup) { + $this->setValidationGroup($validationGroup); + } + } + + return parent::isValid(); + } } diff --git a/src/ZfcUserAdmin/Form/EditUser.php b/src/ZfcUserAdmin/Form/EditUser.php index f59d021..e553e7b 100644 --- a/src/ZfcUserAdmin/Form/EditUser.php +++ b/src/ZfcUserAdmin/Form/EditUser.php @@ -2,14 +2,14 @@ namespace ZfcUserAdmin\Form; -use ZfcUser\Entity\UserInterface; -use ZfcUser\Form\Register; +use Zend\Stdlib\Hydrator\ClassMethods; +use Zend\InputFilter\InputFilter; use ZfcUser\Options\RegistrationOptionsInterface; +use ZfcUser\Entity\UserInterface; +use ZfcUser\Form\Base; use ZfcUserAdmin\Options\UserEditOptionsInterface; -use Zend\Form\Form; -use Zend\Form\Element; -class EditUser extends Register +class EditUser extends Base { /** * @var \ZfcUserAdmin\Options\UserEditOptionsInterface @@ -23,6 +23,11 @@ public function __construct($name = null, UserEditOptionsInterface $options, Reg $this->setUserEditOptions($options); $this->setServiceManager($serviceManager); parent::__construct($name, $registerOptions); + // ZfcUser should have setHydrator() which we replace or extend + $this->setHydrator($serviceManager->get('zfcuser_user_hydrator')); + + // Render using ZfcAdmin form class + $this->setAttribute('class', 'zend_form'); $this->remove('captcha'); @@ -30,14 +35,21 @@ public function __construct($name = null, UserEditOptionsInterface $options, Reg $this->add(array( 'name' => 'reset_password', 'type' => 'Zend\Form\Element\Checkbox', + 'required' => true, 'options' => array( 'label' => 'Reset password to random', + 'exclude' => true, ), )); $password = $this->get('password'); $password->setAttribute('required', false); - $password->setOptions(array('label' => 'Password (only if want to change)')); + $password->setOptions( + array( + 'label' => 'Password (only if want to change)', + 'exclude' => true, + ) + ); $this->remove('passwordVerify'); } else { @@ -61,41 +73,7 @@ public function __construct($name = null, UserEditOptionsInterface $options, Reg $this->get('submit')->setLabel('Save')->setValue('Save'); - $this->add(array( - 'name' => 'userId', - 'attributes' => array( - 'type' => 'hidden' - ), - )); - } - - public function setUser($userEntity) - { - $this->userEntity = $userEntity; - $this->getEventManager()->trigger('userSet', $this, array('user' => $userEntity)); - } - - public function getUser() - { - return $this->userEntity; - } - - public function populateFromUser(UserInterface $user) - { - foreach ($this->getElements() as $element) { - /** @var $element \Zend\Form\Element */ - $elementName = $element->getName(); - if (strpos($elementName, 'password') === 0) continue; - - $getter = $this->getAccessorName($elementName, false); - if (method_exists($user, $getter)) $element->setValue(call_user_func(array($user, $getter))); - } - - foreach ($this->getUserEditOptions()->getEditFormElements() as $element) { - $getter = $this->getAccessorName($element, false); - $this->get($element)->setValue(call_user_func(array($user, $getter))); - } - $this->get('userId')->setValue($user->getId()); + $this->getEventManager()->trigger('init', $this); } protected function getAccessorName($property, $set = true) @@ -127,4 +105,34 @@ public function getServiceManager() { return $this->serviceManager; } + + /** + * Override isValid() to set an validation group of all elements that do not + * have an 'exclude' option, if at least one element has this option set. + * + * @return boolean + */ + public function isValid() + { + if ($this->hasValidated) { + return $this->isValid; + } + + if ($this->getValidationGroup() === null) { + // Add all non-excluded elements to the validation group + $validationGroup = null; + foreach ($this->getElements() as $element) { + if ($element->getOption('exclude') === false or + ($element->getAttribute('readonly') !== true && $element->getOption('exclude') !== true)) + { + $validationGroup[] = $element->getName(); + } + } + if ($validationGroup) { + $this->setValidationGroup($validationGroup); + } + } + + return parent::isValid(); + } } diff --git a/src/ZfcUserAdmin/Service/User.php b/src/ZfcUserAdmin/Service/User.php index e873818..5d88fd3 100644 --- a/src/ZfcUserAdmin/Service/User.php +++ b/src/ZfcUserAdmin/Service/User.php @@ -41,27 +41,21 @@ class User extends EventProvider implements ServiceManagerAwareInterface /** * @param Form $form * @param array $data - * @return UserInterface|null + * @param UserInterface $user + * @return UserInterface */ - public function create(Form $form, array $data) + public function create(Form $form, array $data, UserInterface $user) { - $zfcUserOptions = $this->getZfcUserOptions(); - $user = $form->getData(); - $argv = array(); if ($this->getOptions()->getCreateUserAutoPassword()) { $argv['password'] = $this->generatePassword(); } else { - $argv['password'] = $user->getPassword(); + $argv['password'] = $data['password']; } - $bcrypt = new Bcrypt; - $bcrypt->setCost($zfcUserOptions->getPasswordCost()); + $bcrypt = new Bcrypt(); + $bcrypt->setCost($this->getZfcUserOptions()->getPasswordCost()); $user->setPassword($bcrypt->create($argv['password'])); - foreach ($this->getOptions()->getCreateFormElements() as $element) { - call_user_func(array($user, $this->getAccessorName($element)), $data[$element]); - } - $argv += array('user' => $user, 'form' => $form, 'data' => $data); $this->getEventManager()->trigger(__FUNCTION__, $this, $argv); $this->getUserMapper()->insert($user); @@ -77,18 +71,10 @@ public function create(Form $form, array $data) */ public function edit(Form $form, array $data, UserInterface $user) { - // first, process all form fields - foreach ($data as $key => $value) { - if ($key == 'password') continue; - - $setter = $this->getAccessorName($key); - if (method_exists($user, $setter)) call_user_func(array($user, $setter), $value); - } - $argv = array(); // then check if admin wants to change user password if ($this->getOptions()->getAllowPasswordChange()) { - if (!empty($data['reset_password'])) { + if (!empty($data['generate_password'])) { $argv['password'] = $this->generatePassword(); } elseif (!empty($data['password'])) { $argv['password'] = $data['password']; @@ -101,11 +87,6 @@ public function edit(Form $form, array $data, UserInterface $user) } } - // TODO: not sure if this code is required here - all fields that came from the form already saved - foreach ($this->getOptions()->getEditFormElements() as $element) { - call_user_func(array($user, $this->getAccessorName($element)), $data[$element]); - } - $argv += array('user' => $user, 'form' => $form, 'data' => $data); $this->getEventManager()->trigger(__FUNCTION__, $this, $argv); $this->getUserMapper()->update($user); @@ -121,15 +102,6 @@ public function generatePassword() return Rand::getString($this->getOptions()->getAutoPasswordLength()); } - protected function getAccessorName($property, $set = true) - { - $parts = explode('_', $property); - array_walk($parts, function (&$val) { - $val = ucfirst($val); - }); - return (($set ? 'set' : 'get') . implode('', $parts)); - } - public function getUserMapper() { if (null === $this->userMapper) {