/**
  * Returns an array of variants.
  *
  * With no arguments, returns all variants
  *
  * With a classname as the first argument, returns the variants that apply to that class
  * (optionally including subclasses)
  *
  * @static
  * @param string $class - The class name to get variants for
  * @param bool $includeSubclasses - True if variants should be included if they apply to at least one subclass of $class
  * @return array - An array of (string)$variantClassName => (Object)$variantInstance pairs
  */
 public static function variants($class = null, $includeSubclasses = true)
 {
     if (!$class) {
         if (self::$variants === null) {
             $classes = ClassInfo::subclassesFor('SearchVariant');
             $concrete = array();
             foreach ($classes as $variantclass) {
                 $ref = new ReflectionClass($variantclass);
                 if ($ref->isInstantiable()) {
                     $variant = singleton($variantclass);
                     if ($variant->appliesToEnvironment()) {
                         $concrete[$variantclass] = $variant;
                     }
                 }
             }
             self::$variants = $concrete;
         }
         return self::$variants;
     } else {
         $key = $class . '!' . $includeSubclasses;
         if (!isset(self::$class_variants[$key])) {
             self::$class_variants[$key] = array();
             foreach (self::variants() as $variantclass => $instance) {
                 if ($instance->appliesTo($class, $includeSubclasses)) {
                     self::$class_variants[$key][$variantclass] = $instance;
                 }
             }
         }
         return self::$class_variants[$key];
     }
 }
 /**
  * Given an object and a field definition (as returned by fieldData) get the current value of that field on that object
  *
  * @param DataObject $object - The object to get the value from
  * @param Array $field - The field definition to use
  * @return Mixed - The value of the field, or null if we couldn't look it up for some reason
  */
 protected function _getFieldValue($object, $field)
 {
     set_error_handler(create_function('$no, $str', 'throw new Exception("HTML Parse Error: ".$str);'), E_ALL);
     try {
         foreach ($field['lookup_chain'] as $step) {
             // Just fail if we've fallen off the end of the chain
             if (!$object) {
                 return null;
             }
             // If we're looking up this step on an array or SS_List, do the step on every item, merge result
             if (is_array($object) || $object instanceof SS_List) {
                 $next = array();
                 foreach ($object as $item) {
                     if ($step['call'] == 'method') {
                         $method = $step['method'];
                         $item = $item->{$method}();
                     } else {
                         $property = $step['property'];
                         $item = $item->{$property};
                     }
                     if ($item instanceof SS_List) {
                         $next = array_merge($next, $item->toArray());
                     } elseif (is_array($item)) {
                         $next = array_merge($next, $item);
                     } else {
                         $next[] = $item;
                     }
                 }
                 $object = $next;
             } else {
                 if ($step['call'] == 'method') {
                     $method = $step['method'];
                     $object = $object->{$method}();
                 } elseif ($step['call'] == 'variant') {
                     $variants = SearchVariant::variants($field['base'], true);
                     $variant = $variants[$step['variant']];
                     $method = $step['method'];
                     $object = $variant->{$method}($object);
                 } else {
                     $property = $step['property'];
                     $object = $object->{$property};
                 }
             }
         }
     } catch (Exception $e) {
         $object = null;
     }
     restore_error_handler();
     return $object;
 }