/**
     * @param array $id
     * @return array
     * @throws Rest_Model_Exception
     */
    public function get(array $id, array $params = null)
    {
        if (isset($params['entourage'])) {
            require_once 'models/AclHandler/Entourage.php';
            $entourageHandler = new Default_Model_AclHandler_Entourage($this->getAcl(), $this->getAclContextUser());
            return $entourageHandler->get($id, array($this, $params['entourage']));
        }

        try {

            $this->_assertAllowed('get', $id);

        } catch (Rest_Model_UnauthorizedException $e) {
            // resources are secret if not Acl approved, say it doesn't exist
            throw new Rest_Model_NotFoundException();
        }

        $item = $this->_get($id);

        $this->_assertDependencyAllowed('get', $item);

        return $item;
    }
    /**
     * @param array $params
     * @return array
     */
    public function getList(array $params = null)
    {
        require_once 'Util/Sql.php';
        require_once 'Util/Array.php';

        $params = is_array($params) ? $params : array();

        if (isset($params['entourage'])) {
            require_once 'models/AclHandler/Entourage.php';
            $entourageHandler = new Default_Model_AclHandler_Entourage($this->getAcl(), $this->getAclContextUser());
            $data = $entourageHandler->getList(array($this->_resourceName => $params));
            return $data[$this->_resourceName];
        }

        if (isset($params['where'])) {
            // use default properties to search against if none are provided
            if (!is_array($params['where'])) {
                // no where terms specified, use the defaults at the 'or' level
                $defaultWhereStruct = array();
                foreach ($this->_defaultListWhere as $whereTerm) {
                    $defaultWhereStruct[] = array($whereTerm => $params['where']);
                }
                $params['where'] = array($defaultWhereStruct);
            }
        } else {
            $params['where'] = array();
        }

        if (!isset($params['sort']) || (!is_string($params['sort']) && !is_array($params['sort']))) {
            $params['sort'] = $this->_defaultListSort;
        }
        $params['sort'] = Util_Sql::generateSqlOrderBy($params['sort'], $this->getPropertyKeys());

        // expected that: 0 < limit <= _listMaxLength
        if (!isset($params['limit']) || 0 >= $params['limit'] || $this->_listMaxLength < $params['limit']) {
            $params['limit'] = $this->_listMaxLength;
        }
        $params['limit'] = (integer) $params['limit'];

        // group by
        if (!isset($params['groupBy']) || !in_array($params['groupBy'], $this->getPropertyKeys())) {
            $params['groupBy'] = null;
        }

        // order of elements before group by, determines which row gets used
        // by group by from within the group, the last in the group wins
        if (!isset($params['condenseOn']) || (!is_string($params['condenseOn']) && !is_array($params['condenseOn']))) {
            $params['condenseOn'] = $this->_defaultListSort;
        }
        $params['condenseOn'] = Util_Sql::generateSqlOrderBy($params['condenseOn'], $this->getPropertyKeys());

        // properties is expected to be an array of string property keys or a
        // string of space separated property keys
        //
        // array('id', 'discussion_id', 'comment', 'modified')
        //   - or -
        // 'id discussion_id comment modified'
        {
            if (!isset($params['properties'])) {
                $params['properties'] = $this->getPropertyKeys();
            }
            if (!is_array($params['properties'])) {
                $params['properties'] = explode(' ', $params['properties']);
            }
            $validatedProps = array_intersect($this->getPropertyKeys(), $params['properties']);
            if (count($validatedProps) != count($params['properties'])) {
                require_once 'Rest/Model/BadRequestException.php';
                throw new Rest_Model_BadRequestException('[' . implode(', ', array_diff($params['properties'], $validatedProps)) . '] are not valid properties for ' . $this->_resourceName);
            }
        }

        // this is an optimization. Imposes a slight overhead performance hit,
        // but for queries where there is very restrictive dependency and a
        // large resource set being scanned, this optimization is very important
        if (0 < count($this->_permissionDependency)) {
            // go through all the dependies and make sure there are WHERE
            // clauses for them
            foreach ($this->_permissionDependency as $depResource => $depAssoc) {
                foreach ($depAssoc as $depId => $resourceId) {
                    // if there is a WHERE already for the resource id
                    // associated with the dependency, then can't optimize further
                    if (in_array($resourceId, array_keys($params['where']))) {
                        continue;
                    }

                    $parentResourceHandler = $this->_createAclHandler($depResource);
                    $list = Util_Array::arrayFromKeyValuesOfSet($depId, $parentResourceHandler->getList(array('limit' => $this->_listMaxLength)));

                    if (0 == count($list)) {
                        // none of the dependencies, done
                        return array();
                    }

                    if ($this->_listMaxLength == count($list)) {
                        // optimization isn't optimal in this situation abort
                        // for dependency association
                        continue;
                    }

                    $params['where'][$resourceId] = $list;
                }
            }
        }

        $whereSqlAndParam = Util_Sql::generateSqlWheresAndParams($params['where'], $this->getPropertyKeys());

        $limit = $params['limit'];
        $dbLimit = floor($limit * $this->_listPermissionFilteredRate);

        $cumulativeRowSet = array();
        $offset = 0;
        do {
            $sql = '';
            // do sub select in order to handle sub ordering in group and get
            // the row we want
            $sql .= (($params['groupBy'] && $params['condenseOn']) ? ' SELECT * FROM (' : '');

            // RESOURCE
            $sql .= $this->_getListResourceSqlFragment();

            $sql .= ''
                // ACL
                . $this->_getGenericAclListJoins()

                // ACL
                . ' WHERE ' . $this->_getGenericAclListWheres()

                // RESOURCE
                . ' AND ' . $whereSqlAndParam['sql']
                . ($params['groupBy'] ? (($params['condenseOn'] ? (' ORDER BY ' . implode(', ', $params['condenseOn']) . ')') : '') . ' GROUP BY ' . $params['groupBy']) : '')
                . ' ORDER BY ' . implode(', ', $params['sort'])
                . ' LIMIT ' . $dbLimit
                . ' OFFSET ' . $offset

                . '';
            $query = $this->_getDbHandler()->prepare($sql);
            $query->execute(array_merge($this->_getGenericAclListParams(), $whereSqlAndParam['param']));
            $rowSet = $query->fetchAll(PDO::FETCH_ASSOC);

            $countUnfiltered = count($rowSet);

            $this->_filterDependenciesNotAllowed($rowSet);

            $cumulativeRowSet += $rowSet;

            $countCumulativeFiltered = count($cumulativeRowSet);

            $offset += $dbLimit;
        } while ($countCumulativeFiltered < $limit && $countUnfiltered == $dbLimit);

        // ensure that only the desired properties are returned
        if (!empty($cumulativeRowSet) && count($params['properties']) != count($cumulativeRowSet[0])) {
            foreach ($cumulativeRowSet as &$row) {
                $row = array_intersect_key($row, array_flip($params['properties']));
            }
        }

        return array_slice($cumulativeRowSet, 0, $limit);
    }