/**
  * cache proxy method for DataObjectHelper
  * @return [type] [description]
  */
 protected static function extended_classes()
 {
     $key = 'extended_classes';
     if (empty(static::$cache[$key])) {
         static::$cache[$key] = DataObjectHelper::getExtendedClasses('Taggable');
     }
     return static::$cache[$key];
 }
 /**
  * [getTaggedWith description]
  * @param [type]  $tags       [description]
  * @param [type]  $filterSql  [description]
  * @param integer $start      [description]
  * @param integer $limit      [description]
  * @param string  $lookupMode if AND then you get content tagged with all ptovided tags
  *                            if OR then you get content tagged with at least one of the provided tags
  */
 public static function getTaggedWith($tags, $filterSql = null, $start = 0, $limit = 40, $lookupMode = 'OR')
 {
     // clean up input
     if (!is_array($tags)) {
         $tags = array($tags);
     }
     if ($lookupMode != 'AND' && $lookupMode != 'OR') {
         throw new Exception('Invalid lookupMode supplied');
     }
     // Set some vars
     $classes = DataObjectHelper::getExtendedClasses('Taggable');
     $set = new ArrayList();
     $db = AbcDB::getInstance();
     $sql = '';
     $tables = $joins = $filter = array();
     // Build Query Data
     foreach ($classes as $className) {
         // Fetch Class Data
         $table = DataObjectHelper::getTableForClass($className);
         $extTable = DataObjectHelper::getExtensionTableForClassWithProperty($className, 'Tags');
         // $tables we are working with
         if ($table) {
             $tables[$table] = $table;
         }
         // join
         if ($table && $extTable && $table != $extTable) {
             $joins[$table][] = $extTable;
         } elseif ($extTable) {
             $tables[$extTable] = $extTable;
         }
         // Where
         if ($table) {
             $where[$table][] = $table . ".ClassName = '" . $className . "'";
         }
         // Tag filter
         // Should be REGEX so we don't get partial matches
         if ($extTable) {
             foreach ($tags as $tag) {
                 $filter[$table][] = $extTable . ".Tags REGEXP '(^|,| )+" . Convert::raw2sql($tag) . "(\$|,| )+'";
             }
         }
     }
     // Build Query
     foreach ($tables as $table) {
         if (array_key_exists($table, $joins)) {
             // Prepare Where Statement
             $uWhere = array_unique($where[$table]);
             $uFilter = array_unique($filter[$table]);
             // this lookupMode injection will prob break something in AND mode
             $wSql = "(" . implode(' OR ', $uWhere) . ") AND (" . implode(' ' . $lookupMode . ' ', $uFilter) . ")";
             // Make the rest of the SQL
             if ($sql) {
                 $sql .= "UNION ALL" . "\n\n";
             }
             $rowCountSQL = !$sql ? "SQL_CALC_FOUND_ROWS " : "";
             $sql .= "SELECT " . $rowCountSQL . $table . ".ClassName, " . $table . ".ID" . "\n";
             $sql .= "FROM " . $table . "\n";
             // join
             $join = array_unique($joins[$table]);
             foreach ($join as $j) {
                 $sql .= " LEFT JOIN " . $j . " ON " . $table . ".ID = " . $j . ".ID" . "\n";
             }
             // Add the WHERE statement
             $sql .= "WHERE " . $wSql . "\n\n";
         }
     }
     // Add Global Filter to Query
     if ($filterSql) {
         $sql .= (count($tables) == 1 ? "AND " : "WHERE ") . $filterSql;
     }
     // Add Limits to Query
     $sql .= " LIMIT " . $start . "," . $limit;
     // Get Data
     // die($sql);
     $result = $db->query($sql);
     $result = $result ? $result->fetchAll(PDO::FETCH_OBJ) : array();
     // Convert to DOs
     foreach ($result as $entry) {
         // Make the data easier to work with
         $entry = (object) $entry;
         $className = $entry->ClassName;
         // this is faster but might not pull in relations
         //$dO = new $className;
         //$dO = DataObjectHelper::populate($dO, $entry);
         // this is slower, but will be more reliable
         $dO = DataObject::get_by_id($className, $entry->ID);
         $set->push($dO);
     }
     $set->unlimitedRowCount = $db->query('SELECT FOUND_ROWS() AS total')->fetch(PDO::FETCH_OBJ)->total;
     return $set;
 }