ecml_current_view = $view; return preg_replace_callback(ECML_KEYWORD_REGEX, 'ecml_parse_view_match', $string); } /** * Returns ECML-style keywords found in $string. * Doesn't validate them. * Returns an array of keyword => arguments * * @param string $string * @return array */ function ecml_extract_keywords($string) { $return = array(); if (preg_match_all(ECML_KEYWORD_REGEX, $string, $matches)) { foreach ($matches[1] as $i => $keyword) { $return[] = array('keyword' => $keyword, 'params' => $matches[2][$i]); } } return $return; } /** * Parse ECML keywords * * @param array $matches * @return string html */ function ecml_parse_view_match($matches) { global $CONFIG; $view = $CONFIG->ecml_current_view; $keyword = trim($matches[1]); $params_string = trim($matches[2]); // reject keyword if blacklisted for view or invalid if (!ecml_is_valid_keyword($keyword, $view)) { return $matches[0]; } switch ($keyword) { case 'entity_list': $options = ecml_keywords_parse_entity_params($params_string); // must use this lower-level function because I missed refactoring // the list entity functions for relationships. // (which, since you're here, is the only function that runs through all // possible options for elgg_get_entities*() functions...) $entities = elgg_get_entities_from_relationship($options); $content = elgg_view_entity_list($entities, count($entities), $options['offset'], $options['limit'], $options['full_view'], $options['list_type_toggle'], $options['pagination']); break; case 'view': // src is a required attribute of view $vars = ecml_keywords_tokenize_params($params_string); $vars['ecml_keyword'] = $keyword; $vars['ecml_params_string'] = $params_string; $content = elgg_view($vars['src'], $vars); break; default: // match against custom keywords with optional args $keyword_info = $CONFIG->ecml_keywords[$keyword]; $vars = ecml_keywords_tokenize_params($params_string); $vars['ecml_keyword'] = $keyword; $vars['ecml_params_string'] = $params_string; $content = elgg_view($keyword_info['view'], $vars); break; } // if nothing matched return the original string. // @todo this might be undesirable. will show ugly code everywhere // if you delete a file or something. if (!$content) { $content = $matches[0]; } return $content; } /** * Creates an array from a name=value name2='value2' name3="value3" string. * * @param $string * @return array */ function ecml_keywords_tokenize_params($string) { if (empty($string)) { return array(); } $params = array(); $pos = 0; $char = substr($string, $pos, 1); // working var for assembling name and values $operand = $name = ''; while ($char !== FALSE) { switch ($char) { // handle quoted names/values case '"': case "'": $quote = $char; $next_char = substr($string, ++$pos, 1); while ($next_char != $quote) { if ($next_char === FALSE) { // no matching quote. bail. return array(); } $operand .= $next_char; $next_char = substr($string, ++$pos, 1); } break; case ECML_ATTR_SEPARATOR: // normalize true and false if ($operand == 'true'){ $operand = TRUE; } elseif ($operand == 'false') { $operand = FALSE; } $params[$name] = $operand; $operand = $name = ''; break; case ECML_ATTR_OPERATOR: // save name, switch to value $name = $operand; $operand = ''; break; default: $operand .= $char; } $char = substr($string, ++$pos, 1); } // need to get the last attr if ($name && $operand) { if ($operand == 'true'){ $operand = TRUE; } elseif ($operand == 'false') { $operand = FALSE; } $params[$name] = $operand; } return $params; // this is much faster, but doesn't allow quoting. // $pairs = array_map('trim', explode(',', $string)); // $params = array(); // // foreach ($pairs as $pair) { // list($name, $value) = explode('=', $pair); // // $name = trim($name); // $value = trim($value); // // // normalize BOOL values // if ($value === 'true') { // $value = TRUE; // } elseif ($value === 'false') { // $value = FALSE; // } // // // don't check against value since a falsy/empty value is valid. // if ($name) { // $params[$name] = $value; // } // } // // return $params; } /** * Returns an options array suitable for using in elgg_get_entities() * * @param string $string "name=value, name2=value2" * @return array */ function ecml_keywords_parse_entity_params($string) { $params = ecml_keywords_tokenize_params($string); // handle some special cases if (isset($params['owner'])) { if ($user = get_user_by_username($params['owner'])) { $params['owner_guid'] = $user->getGUID(); } } // @todo probably need to add more for // group -> container_guid, etc return $params; } /** * Checks granular permissions if keyword is valid for view * * @param unknown_type $keyword * @param unknown_type $view * @return bool */ function ecml_is_valid_keyword($keyword, $view = NULL) { global $CONFIG; // this isn't even a real keyword. if (!isset($CONFIG->ecml_keywords[$keyword])) { return FALSE; } // don't check against views. Already know it's a real one. if (!$view) { return TRUE; } // this keyword is restricted to certain views if (isset($CONFIG->ecml_keywords[$keyword]['restricted']) && !in_array($view, $CONFIG->ecml_keywords[$keyword]['restricted'])) { return FALSE; } $views = $CONFIG->ecml_permissions; // this is a blacklist, so return TRUE by default. $r = TRUE; if (isset($views[$view]) && in_array($keyword, $views[$view])) { $r = FALSE; } return $r; } /** * Grab the ECML keywords as saved in $CONFIG or regenerate. */ function ecml_get_keywords($recache = FALSE) { global $CONFIG; if (isset($CONFIG->ecml_keywords) && !$recache) { return $CONFIG->ecml_keywords; } $keywords = elgg_trigger_plugin_hook('get_keywords', 'ecml', NULL, array()); $CONFIG->ecml_keywords = $keywords; return $keywords; } /** * Return basic info about the keyword. * * @param string $keyword * @return array */ function ecml_get_keyword_info($keyword) { global $CONFIG; if (isset($CONFIG->ecml_keywords[$keyword])) { return $CONFIG->ecml_keywords[$keyword]; } return FALSE; }