+ /**
+ * Given a set of links and a mask, return a filtered (by mask) array containing the final links with parsed values
+ * and calling hooks as appropriate.
+ * Use this when passing a set of action links to the API or to the form without adding html formatting.
+ *
+ * @param array $links
+ * The set of link items.
+ * @param int $mask
+ * The mask to be used. a null mask means all items.
+ * @param array $values
+ * The array of values for parameter substitution in the link items.
+ * @param null $op
+ * @param null $objectName
+ * @param int $objectId
+ *
+ * @return array|null
+ * The array describing each link
+ */
+ public static function filterLinks(
+ $links,
+ $mask,
+ $values,
+ $op = NULL,
+ $objectName = NULL,
+ $objectId = NULL
+ ) {
+ if (empty($links)) {
+ return NULL;
+ }
+
+ // make links indexed sequentially instead of by bitmask
+ // otherwise it's next to impossible to reliably add new ones
+ $seqLinks = array();
+ foreach ($links as $bit => $link) {
+ $link['bit'] = $bit;
+ $seqLinks[] = $link;
+ }
+
+ if ($op && $objectName && $objectId) {
+ CRM_Utils_Hook::links($op, $objectName, $objectId, $seqLinks, $mask, $values);
+ }
+
+ foreach ($seqLinks as $i => $link) {
+ if (!$mask || !array_key_exists('bit', $link) || ($mask & $link['bit'])) {
+ $seqLinks[$i]['extra'] = isset($link['extra']) ? self::replace($link['extra'], $values) : NULL;
+
+ if (isset($link['qs']) && !CRM_Utils_System::isNull($link['qs'])) {
+ $seqLinks[$i]['url'] = self::replace($link['url'], $values);
+ $seqLinks[$i]['qs'] = self::replace($link['qs'], $values);
+ }
+ }
+ else {
+ unset($seqLinks[$i]);
+ }
+ }
+
+ return $seqLinks;
+ }
+