From: <gem...@li...> - 2012-07-18 08:01:15
|
Revision: 852 http://gemstracker.svn.sourceforge.net/gemstracker/?rev=852&view=rev Author: mennodekker Date: 2012-07-18 08:01:04 +0000 (Wed, 18 Jul 2012) Log Message: ----------- Fixed #549: Allow a layered login when organizations have children Modified Paths: -------------- trunk/library/classes/Gems/Default/IndexAction.php trunk/library/classes/Gems/User/Form/OrganizationFormAbstract.php trunk/library/classes/Gems/User/UserLoader.php Added Paths: ----------- trunk/library/classes/Gems/User/Form/LayeredLoginForm.php Modified: trunk/library/classes/Gems/Default/IndexAction.php =================================================================== --- trunk/library/classes/Gems/Default/IndexAction.php 2012-07-17 15:55:22 UTC (rev 851) +++ trunk/library/classes/Gems/Default/IndexAction.php 2012-07-18 08:01:04 UTC (rev 852) @@ -56,6 +56,14 @@ protected $labelWidthFactor = null; /** + * Use a flat login (false = default) or a layered login where you first + * select a parent organization and then see a list of child organizations. + * + * @var boolean + */ + protected $layeredLogin = false; + + /** * For small numbers of organizations a multiline selectbox will be nice. This * setting handles how many lines will display at once. Use 1 for the normal * dropdown selectbox @@ -108,7 +116,11 @@ Gems_Html::init(); - return $this->loader->getUserLoader()->getLoginForm($args); + if ($this->layeredLogin === true) { + return $this->loader->getUserLoader()->getLayeredLoginForm($args); + } else { + return $this->loader->getUserLoader()->getLoginForm($args); + } } /** @@ -208,7 +220,7 @@ $previousRequestParameters = $staticSession->previousRequestParameters; $previousRequestMode = $staticSession->previousRequestMode; - if ($request->isPost()) { + if ($form->wasSubmitted()) { if ($form->isValid($request->getPost(), false)) { $user = $form->getUser(); $user->setAsCurrentUser(); @@ -258,6 +270,10 @@ $log = Gems_AccessLog::getLog(); $log->log('loginFail', $this->getRequest(), $msg, null, true); } // */ + } else { + if ($request->isPost()) { + $form->populate($this->getRequest()->getPost()); + } } $this->displayLoginForm($form); Added: trunk/library/classes/Gems/User/Form/LayeredLoginForm.php =================================================================== --- trunk/library/classes/Gems/User/Form/LayeredLoginForm.php (rev 0) +++ trunk/library/classes/Gems/User/Form/LayeredLoginForm.php 2012-07-18 08:01:04 UTC (rev 852) @@ -0,0 +1,248 @@ +<?php + +/** + * Copyright (c) 2011, Erasmus MC + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of Erasmus MC nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Short description of file + * + * @package Gems + * @subpackage + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @version $Id: Sample.php 215 2011-07-12 08:52:54Z michiel $ + */ + +/** + * Short description for LoginForm + * + * Long description for class LoginForm (if any)... + * + * @package Gems + * @subpackage Sample + * @copyright Copyright (c) 2011 Erasmus MC + * @license New BSD License + * @since Class available since version 1.0 + * @deprecated Class deprecated since version 2.0 + */ +class Gems_User_Form_LayeredLoginForm extends Gems_User_Form_LoginForm +{ + /** + * @var Zend_Db_Adapter_Abstract + */ + public $db; + + /** + * The field name for the top organization element. + * + * @var string + */ + public $topOrganizationFieldName = 'toporganization'; + + /** + * Return array of organizations that are a child of the given parentId + * + * @param int $parentId + * @return array + */ + public function getChildOrganisations($parentId = null) + { + if (is_null($parentId)) { + return array(); + } + + try { + $organizations = $this->db->fetchPairs('SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active=1 AND gor_has_login=1 AND (gor_accessible_by LIKE ' . $this->db->quote(':' . $parentId . ':') . ' OR gor_id_organization = ' . $this->db->quote($parentId) . ') ORDER BY gor_name'); + } catch (Exception $e) { + try { + // 1.4 fallback + $organizations = $this->db->fetchPairs('SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active=1 AND (gor_accessible_by LIKE ' . $this->db->quote(':' . $parentId . ':') . ' OR gor_id_organization = ' . $this->db->quote($parentId) . ') ORDER BY gor_name'); + } catch (Exception $e) { + $organizations = array(); + } + } + + natsort($organizations); + + return $organizations; + } + + /** + * Returns the top organization id that should currently be used for this form. + * + * @return int Returns the current organization id, if any + */ + public function getCurrentTopOrganizationId() + { + $userLoader = $this->loader->getUserLoader(); + + // Url determines organization first. + if ($orgId = $userLoader->getOrganizationIdByUrl()) { + $this->_organizationFromUrl = true; + return ' '; + } + + $request = $this->getRequest(); + if ($request->isPost() && ($orgId = $request->getParam($this->topOrganizationFieldName))) { + Gems_Cookies::set('gems_toporganization', $orgId); + return $orgId; + } else { + return Gems_Cookies::get($this->getRequest(), 'gems_toporganization', ' '); + } + } + + /** + * Returns/sets an element for determining / selecting the organization. + * + * Depends on the top-organization + * + * @return Zend_Form_Element_Xhtml + */ + public function getOrganizationElement() + { + $element = $this->getElement($this->organizationFieldName); + $orgId = $this->getCurrentOrganizationId(); + $parentId = $this->getCurrentTopOrganizationId(); + $childOrgs = $this->getChildOrganisations($parentId); + + if (!empty($childOrgs)) { + if (count($childOrgs) == 1) { + $element = new Zend_Form_Element_Hidden($this->organizationFieldName); + $this->addElement($element); + + if (! $this->_organizationFromUrl) { + $orgIds = array_keys($childOrgs); + $orgId = reset($orgIds); + } + + $element->setValue($orgId); + $this->getRequest()->setPost($this->organizationFieldName, $orgId); + + } else { + $element = new Zend_Form_Element_Select($this->organizationFieldName); + $element->setLabel($this->translate->_('Organization')); + $element->setRegisterInArrayValidator(true); + $element->setRequired(true); + $element->setMultiOptions($childOrgs); + + if ($this->organizationMaxLines > 1) { + $element->setAttrib('size', min(count($orgs) + 1, $this->organizationMaxLines)); + } + $this->addElement($element); + $element->setValue($orgId); + } + } + + return $element; + } + + /** + * Return a list of organizations that are considered top-organizations, in this + * case organizations that are not accessible by others as they are considered + * the children of the top organizations. Feel free to modify to suit your + * needs. + * + * @return array + */ + public function getTopOrganisations() + { + try { + $organizations = $this->db->fetchPairs('SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active=1 AND gor_has_login=1 AND gor_accessible_by IS NULL ORDER BY gor_name'); + } catch (Exception $e) { + try { + // 1.4 fallback + $organizations = $this->db->fetchPairs('SELECT gor_id_organization, gor_name FROM gems__organizations WHERE gor_active=1 AND gor_accessible_by IS NULL ORDER BY gor_name'); + } catch (Exception $e) { + $organizations = array(); + } + } + + natsort($organizations); + + return $organizations; + } + + + /** + * Returns/sets an element for determining / selecting the top-organization. + * + * @return null|\Zend_Form_Element_Select + */ + public function getTopOrganizationElement() + { + $element = $this->getElement($this->topOrganizationFieldName); + $orgId = $this->getCurrentTopOrganizationId(); + $orgs = $this->getTopOrganisations(); + $hidden = $this->_organizationFromUrl || (count($orgs) < 2); + + if ($this->_organizationFromUrl) { + return null; + } + + if ($hidden) { + if (! $element instanceof Zend_Form_Element_Hidden) { + $element = new Zend_Form_Element_Hidden($this->topOrganizationFieldName); + $this->addElement($element); + } + + $orgIds = array_keys($orgs); + $orgId = reset($orgIds); + + $element->setValue($orgId); + + } elseif (! $element instanceof Zend_Form_Element_Select) { + $element = new Zend_Form_Element_Select($this->topOrganizationFieldName); + $element->setLabel($this->translate->_('Organization')); + $element->setRegisterInArrayValidator(true); + $element->setRequired(true); + $element->setMultiOptions($orgs); + $element->setAttrib('onchange', 'this.form.submit();'); + + if ($this->organizationMaxLines > 1) { + $element->setAttrib('size', min(count($orgs) + 1, $this->organizationMaxLines)); + } + $this->addElement($element); + + $element->setValue($orgId); + } + + return $element; + } + + /** + * Load the elements, starting with the extra top organization element and + * continue with the other elements like in the standard login form + * + * @return Gems_User_Form_LayeredLoginForm + */ + public function loadDefaultElements() + { + $this->getTopOrganizationElement(); + + parent::loadDefaultElements(); + + return $this; + } +} \ No newline at end of file Modified: trunk/library/classes/Gems/User/Form/OrganizationFormAbstract.php =================================================================== --- trunk/library/classes/Gems/User/Form/OrganizationFormAbstract.php 2012-07-17 15:55:22 UTC (rev 851) +++ trunk/library/classes/Gems/User/Form/OrganizationFormAbstract.php 2012-07-18 08:01:04 UTC (rev 852) @@ -284,6 +284,12 @@ */ public function wasSubmitted() { - return $this->getSubmitButton()->isChecked(); + // If form was not (yet) populated, we can not use isChecked() so do this manually + $request = $this->getRequest(); + if ($request->isPost() && $request->getPost($this->_submitFieldName) == $this->getSubmitButtonLabel()) { + return true; + } else { + return false; + } } } Modified: trunk/library/classes/Gems/User/UserLoader.php =================================================================== --- trunk/library/classes/Gems/User/UserLoader.php 2012-07-17 15:55:22 UTC (rev 851) +++ trunk/library/classes/Gems/User/UserLoader.php 2012-07-18 08:01:04 UTC (rev 852) @@ -305,6 +305,20 @@ } /** + * Returns a layered login form where user first selects a top organization and then a + * child organization + * + * @param mixed $args_array MUtil_Ra::args array for LoginForm initiation. + * @return Gems_User_Form_LayeredLoginForm + */ + public function getLayeredLoginForm($args_array = null) + { + $args = MUtil_Ra::args(func_get_args()); + + return $this->_loadClass('Form_LayeredLoginForm', true, array($args)); + } + + /** * Returns a login form * * @param mixed $args_array MUtil_Ra::args array for LoginForm initiation. This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |