private static function generateExtensionMap()
 {
     // get a list of classes
     $classes = array_unique(array_merge(array_keys(ClassInfo::allClasses()), get_declared_classes()));
     // die(print_r($classes,1));
     // Silverstripe has broken clases floating around, we need to blacklist them or it's bad times
     $blacklist = array('SapphireTestReporter', 'SapphireTest', 'SapphireTestSuite', 'CliTestReporter', 'SilverStripeListener', 'TeamCityListener', 'SS_TestListener');
     $blacklistLC = array_map('strtolower', $blacklist);
     // init some vars
     $extMap = $dOClasses = $dODClasses = array();
     // Sort Classes
     foreach ($classes as $class) {
         if (!in_array(strtolower($class), $blacklistLC)) {
             // this breaks when we start looking at some of the broken requires in SapphireTest
             if (is_subclass_of($class, 'DataObject')) {
                 $dOClasses[] = $class;
             }
             if (is_subclass_of($class, 'Extension')) {
                 $dODClasses[] = $class;
             }
         }
     }
     // Find out what is applied to what
     foreach ($dODClasses as $dOD) {
         foreach ($dOClasses as $dO) {
             if (Object::has_extension($dO, $dOD)) {
                 $extMap[$dOD][] = $dO;
             }
         }
     }
     // Cache the map
     self::$extensionMap = $extMap;
 }
 /**
  * cache proxy method for DataObjectHelper
  * @param  [type] $className [description]
  * @param  [type] $prop      [description]
  * @return [type]            [description]
  */
 protected static function extension_table_for_class_with_property($className, $prop)
 {
     $key = 'extension_table_for_class_with_property' . $className . $prop;
     if (empty(static::$cache[$key])) {
         static::$cache[$key] = DataObjectHelper::getExtensionTableForClassWithProperty($className, $prop);
     }
     return static::$cache[$key];
 }
 public static function getUnlimitedRowCount($callerClass, $filter = "", $join = "")
 {
     // Init some vars
     $oTable = $table = DataObjectHelper::getTableForClass($callerClass);
     if (Object::has_extension($callerClass, 'Versioned')) {
         $stage = Versioned::current_stage();
         $table = $oTable . ($stage == 'Live' ? '_' . $stage : '');
     }
     $wSQL = "";
     //$sql = "SELECT COUNT(*) as total FROM ".$table;
     $sql = "SELECT COUNT(*) as total FROM " . SS_SITE_DATABASE_NAME . '.' . $table;
     // join
     if ($join) {
         $sql .= " " . $join;
     }
     if ($oTable != $callerClass && DataObjectHelper::tableExists($callerClass)) {
         $sql .= " LEFT JOIN " . $callerClass . " ON " . $table . ".ID = " . $callerClass . ".ID";
     }
     // Add caller class filter if its on a shared table
     if ($callerClass != $oTable) {
         $wSQL .= $wSQL ? " AND " : " WHERE ";
         $wSQL .= "(" . $table . ".ClassName='" . $callerClass . "'";
         if ($subclasses = DataObjectHelper::getSubclassesOf($callerClass)) {
             foreach ($subclasses as $subclass) {
                 $wSQL .= " OR " . $table . ".ClassName='" . $subclass . "'";
             }
         }
         $wSQL .= ")";
     }
     // Filter
     if ($filter) {
         $wSQL .= $wSQL ? " AND " : " WHERE ";
         $wSQL .= "(" . $filter . ")";
     }
     //finalise
     $sql .= $wSQL;
     return self::getUnlimitedRowCountForSQL($sql);
 }
 /**
  * kind of a wierd thing to add in here
  * @param  [type] $class  [description]
  * @param  [type] $q      [description]
  * @param  array  $fields [description]
  * @return [type]         [description]
  */
 public static function weighted_search($className, $q, array $fields = array('Content' => 1, 'Title' => 3), $start = 0, $limit = 10, $filterSql = null)
 {
     // sort out the cache
     $implodedArgs = $className . '_' . $q . '_' . implode('_', $fields) . '_' . $start . '_' . $limit . '_' . $filterSql;
     $cachekey = preg_replace("/[^A-Za-z0-9]/", '_', __FUNCTION__ . "_" . $implodedArgs);
     $cache = SS_Cache::Factory('DataObjectSearch', 'Output', array('lifetime' => static::get_cache_time(), 'automatic_serialization' => true));
     $set = $cache->load($cachekey);
     // dont hit the db if we don't need to
     if (!$set) {
         // parse terms
         // need to analyse various fragments like first 3 words, last 3 words
         $terms = array_merge(static::str_to_terms($q), static::str_to_fragments($q));
         $terms[] = $q;
         $terms = array_unique($terms);
         // Set some vars
         $set = new ArrayList();
         $db = AbcDB::getInstance();
         $sql = '';
         // expand search to subclasses
         $classes = array_merge(ClassInfo::subclassesFor($className), array($className));
         // iterate through list
         foreach ($classes as $className) {
             // Fetch Class Data
             $table = DataObjectHelper::getTableForClass($className);
             foreach ($fields as $field => $weight) {
                 foreach ($terms as $term) {
                     // init the recivers
                     $tables = $joins = $filter = array();
                     // $tables we are working with
                     if ($table) {
                         $tables[$table] = $table;
                     }
                     // Where
                     if ($table) {
                         $where[$table][] = $table . ".ClassName = '" . $className . "'";
                     }
                     // find the table the property is on
                     $extTable = DataObjectHelper::getExtensionTableForClassWithProperty($className, $field);
                     // join
                     if ($table && $extTable && $table != $extTable) {
                         $joins[$table][] = $extTable;
                     } elseif ($extTable) {
                         $tables[$extTable] = $extTable;
                     }
                     // ext table
                     if ($extTable) {
                         $filter[$table][] = $extTable . "." . $field . " LIKE '%" . Convert::raw2sql($term) . "%'";
                     } else {
                         $filter[$table][] = $table . "." . $field . " LIKE '%" . Convert::raw2sql($term) . "%'";
                     }
                     // Build Query
                     foreach ($tables as $table) {
                         // Prepare Where Statement
                         $uWhere = array_unique($where[$table]);
                         $uFilter = array_unique($filter[$table]);
                         // Where SQL
                         $wSql = "(" . implode(' OR ', $uWhere) . ") AND (" . implode(' OR ', $uFilter) . ")";
                         // Make the rest of the SQL
                         if ($sql) {
                             $sql .= " ) UNION ALL (" . "\n\n";
                         }
                         $sql .= "SELECT " . $table . ".ClassName, " . $table . ".ID,  " . $weight . " AS weight" . "\n";
                         $sql .= "FROM " . $table . "\n";
                         // join
                         if (array_key_exists($table, $joins)) {
                             $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 and order to Query
         $sql = "\n                SELECT SQL_CALC_FOUND_ROWS ClassName, ID, SUM(weight) AS total_weight\n                FROM ((" . $sql . ")) AS t1\n                GROUP BY ID\n                ORDER BY total_weight DESC\n                LIMIT " . $start . "," . $limit . "\n            ";
         // Get Data
         // die('<br>' . $sql . '<br>');
         $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 slower, but will be more reliable
             $dO = DataObject::get_by_id($className, $entry->ID);
             $set->push($dO);
         }
         // stash total length
         $res = $db->query('SELECT FOUND_ROWS() AS total');
         $set->unlimitedRowCount = 0;
         if (!empty($res)) {
             $resObj = $res->fetch(PDO::FETCH_OBJ);
             if (!empty($resObj)) {
                 $set->unlimitedRowCount = $resObj->total;
             }
         }
         // cache
         $cache->save($set, $cachekey);
     }
     return $set;
 }
 /**
  * [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;
 }