/** * This function will parse arguments and hand them back in an array * The defaults are set as part of the class ($defaultLimit, $allowOffsetEnd, $defaultOrderBy, $addDefaultFields, $checkAcls) * * @param ServiceBase $api The API class (typically RestService) * @param array $args The argument array as passed in to the API call, currently checked variables are * max_num, offset, fields, order_by * @param SugarBean|null $seed This is the seed bean that feeds the list, if you pass in a null seed then the fields are not validated * @return array An array with the options limit, offset, fields and order_by set */ public function parseArguments(ServiceBase $api, array $args, $seed = null) { $limit = $this->defaultLimit; if (isset($args['max_num'])) { $limit = (int) $args['max_num']; } $limit = $this->checkMaxListLimit($limit); $offset = 0; if (isset($args['offset'])) { if ($args['offset'] === 'end') { if ($this->allowOffsetEnd) { $offset = 'end'; } else { $offset = 0; } } else { //Do not allow negative offsets $offset = max(0, (int) $args['offset']); } } $userFields = array(); if (!empty($args['fields'])) { $userFields = explode(",", $args["fields"]); } foreach ($this->addDefaultFields as $defaultField) { if (!in_array($defaultField, $userFields)) { $userFields[] = $defaultField; } } $orderBy = ''; if (isset($args['order_by'])) { if (strpos($args['order_by'], ',') !== 0) { // There is a comma, we are ordering by more than one thing $orderBys = explode(',', $args['order_by']); } else { $orderBys = array($args['order_by']); } $orderByArray = array(); foreach ($orderBys as $order) { if (strpos($order, ':')) { // It has a :, it's specifying ASC / DESC list($column, $direction) = explode(':', $order); if (strtolower($direction) == 'desc') { $direction = 'DESC'; } else { $direction = 'ASC'; } } else { // No direction specified, let's let it fly free $column = $order; $direction = 'ASC'; } if ($seed != null) { if ($this->checkAcls && !$seed->ACLFieldAccess($column, 'list')) { throw new SugarApiExceptionNotAuthorized('No access to view field: ' . $column . ' in module: ' . $seed->module_dir); } if (!isset($seed->field_defs[$column])) { throw new SugarApiExceptionNotAuthorized('No access to view field: ' . $column . ' in module: ' . $seed->module_dir); } } $orderByArray[$column] = $direction; } } else { $orderByArray = $this->defaultOrderBy; } return array('limit' => $limit, 'offset' => $offset, 'fields' => $userFields, 'orderBy' => $orderByArray); }
/** * Creates internal representation of ORDER BY expression from API arguments * * @param array $args API arguments * @param SugarBean $seed The bean to validate the value against. * If omitted, no validation is performed * * @return array Associative array where key is field name, boolean value is direction * (TRUE stands for ASC, FALSE stands for DESC) * @throws SugarApiExceptionInvalidParameter * @throws SugarApiExceptionNotAuthorized */ protected function getOrderByFromArgs(array $args, SugarBean $seed = null) { $orderBy = array(); if (!isset($args['order_by']) || !is_string($args['order_by'])) { return $orderBy; } $columns = explode(',', $args['order_by']); $parsed = array(); foreach ($columns as $column) { $column = explode(':', $column, 2); $field = array_shift($column); if ($seed) { if (!isset($seed->field_defs[$field])) { throw new SugarApiExceptionInvalidParameter(sprintf('Non existing field: %s in module: %s', $field, $seed->module_name)); } if (!$seed->ACLFieldAccess($field, 'list')) { throw new SugarApiExceptionNotAuthorized(sprintf('No access to view field: %s in module: %s', $field, $seed->module_name)); } } // do not override previous value if it exists since it should have higher precedence if (!isset($parsed[$field])) { $direction = array_shift($column); $parsed[$field] = strtolower($direction) !== 'desc'; } } return $parsed; }
/** * Formats the bean so it is ready to be handed back to the API's client. Certian fields will get extra processing * to make them easier to work with from the client end. * * @param $bean SugarBean The bean you want formatted * @param $fieldList array Which fields do you want formatted and returned (leave blank for all fields) * @param $options array Currently no options are supported * @return array The bean in array format, ready for passing out the API to clients. */ public function formatForApi(SugarBean $bean, array $fieldList = array(), array $options = array()) { $sfh = new SugarFieldHandler(); // if you are listing something the action is list // if any other format is called its a view $action = !empty($options['action']) && $options['action'] == 'list' ? 'list' : 'view'; $data = array(); $hasAccess = empty($bean->deleted) && $bean->ACLAccess($action); if ($hasAccess) { foreach ($bean->field_defs as $fieldName => $properties) { // Prune fields before ACL check because it can be expensive (Bug58133) if (!empty($fieldList) && !in_array($fieldName, $fieldList)) { // They want to skip this field continue; } if (!$bean->ACLFieldAccess($fieldName, 'read')) { // No read access to the field, eh? Unset the field from the array of data returned unset($data[$fieldName]); continue; } $type = !empty($properties['custom_type']) ? $properties['custom_type'] : $properties['type']; $field = $sfh->getSugarField($type); if (empty($field)) { continue; } if (isset($bean->{$fieldName}) || $type == 'relate') { $field->apiFormatField($data, $bean, $options, $fieldName, $properties, $fieldList, $this->api); } } // mark if its a favorite if (in_array('my_favorite', $fieldList) || empty($fieldList)) { if (isset($bean->my_favorite)) { $data['my_favorite'] = (bool) $bean->my_favorite; } else { // If the module doesn't support favorites, set it to false $data['my_favorite'] = false; } } } else { if (isset($bean->id)) { $data['id'] = $bean->id; } if (isset($bean->deleted) && $bean->deleted == true) { $data['deleted'] = (bool) $bean->deleted; } else { if (isset($bean->date_modified) && !empty($bean->field_defs['date_modified'])) { $field = $sfh->getSugarField($bean->field_defs['date_modified']['type']); $field->apiFormatField($data, $bean, array(), 'date_modified', $bean->field_defs['date_modified'], $fieldList, $this->api); } } if ($this->api->user->isAdmin()) { // BR-759 requests that assigned_user_id is returned on deleted records // to better sync some external systems if (isset($bean->assigned_user_id) && in_array('assigned_user_id', $fieldList)) { $data['assigned_user_id'] = $bean->assigned_user_id; } } } // in some cases the ACL data should be displayed, even when the used doesn't have access to the bean // (e.g. after bean is assigned to a different user and thus is no more accessible) if ($hasAccess || !empty($options['display_acl'])) { // if not an admin and the hashes differ, send back bean specific acl's $data['_acl'] = $this->getBeanAcl($bean, $fieldList); } return $data; }