2012-08-21 04:21:23 +02:00
|
|
|
<?php
|
|
|
|
/**
|
|
|
|
* Finds {@link DataObject} instances using certain shortcodes
|
|
|
|
* by fulltext-querying only fields which are capable of parsing shortcodes.
|
|
|
|
* Effectively the reverse of "link tracking",
|
|
|
|
* which updates this relation on write rather than fetching it on demand.
|
|
|
|
*
|
|
|
|
* Doesn't scale to millions of pages due to triggering a potentially unindexed LIKE
|
|
|
|
* search across dozens of columns and tables - but for a couple of hundred pages
|
|
|
|
* and occasionally use its a feasible solution.
|
|
|
|
*/
|
2015-12-17 19:48:37 +01:00
|
|
|
class ShortCodeRelationFinder
|
|
|
|
{
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
/**
|
|
|
|
* @var String Regex matching a {@link DBField} class name which is shortcode capable.
|
|
|
|
*
|
|
|
|
* This should really look for implementors of a ShortCodeParseable interface,
|
|
|
|
* but we can't extend the core Text and HTMLText class
|
|
|
|
* on existing like SiteTree.Content for this.
|
|
|
|
*/
|
|
|
|
protected $fieldSpecRegex = '/^(HTMLText)/';
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
/**
|
|
|
|
* @param String Shortcode index number to find
|
|
|
|
* @return array IDs
|
|
|
|
*/
|
|
|
|
public function findPageIDs($number)
|
|
|
|
{
|
|
|
|
$list = $this->getList($number);
|
|
|
|
$found = $list->column();
|
|
|
|
return $found;
|
|
|
|
}
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
public function findPageCount($number)
|
|
|
|
{
|
|
|
|
$list = $this->getList($number);
|
|
|
|
return $list->count();
|
|
|
|
}
|
2012-08-21 07:57:06 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
/**
|
|
|
|
* @return DataList
|
|
|
|
*/
|
|
|
|
public function getList($number)
|
|
|
|
{
|
|
|
|
$list = DataList::create('SiteTree');
|
|
|
|
$where = array();
|
|
|
|
$fields = $this->getShortCodeFields('SiteTree');
|
2017-05-17 07:24:50 +02:00
|
|
|
$shortcode = DMS::inst()->getShortcodeHandlerKey();
|
2015-12-17 19:48:37 +01:00
|
|
|
foreach ($fields as $ancClass => $ancFields) {
|
|
|
|
foreach ($ancFields as $ancFieldName => $ancFieldSpec) {
|
|
|
|
if ($ancClass != "SiteTree") {
|
|
|
|
$list = $list->leftJoin($ancClass, '"'.$ancClass.'"."ID" = "SiteTree"."ID"');
|
|
|
|
}
|
2017-05-17 07:24:50 +02:00
|
|
|
$where[] = "\"$ancClass\".\"$ancFieldName\" LIKE '%[{$shortcode},id=$number]%'"; //."%s" LIKE ""',
|
2015-12-17 19:48:37 +01:00
|
|
|
}
|
|
|
|
}
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
$list = $list->where(implode(' OR ', $where));
|
|
|
|
return $list;
|
|
|
|
}
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
/**
|
|
|
|
* Returns a filtered list of fields which could contain shortcodes.
|
|
|
|
*
|
|
|
|
* @param String
|
|
|
|
* @return Array Map of class names to an array of field names on these classes.
|
|
|
|
*/
|
|
|
|
public function getShortcodeFields($class)
|
|
|
|
{
|
|
|
|
$fields = array();
|
|
|
|
$ancestry = array_values(ClassInfo::dataClassesFor($class));
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
foreach ($ancestry as $ancestor) {
|
|
|
|
if (ClassInfo::classImplements($ancestor, 'TestOnly')) {
|
|
|
|
continue;
|
|
|
|
}
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
$ancFields = DataObject::custom_database_fields($ancestor);
|
|
|
|
if ($ancFields) {
|
|
|
|
foreach ($ancFields as $ancFieldName => $ancFieldSpec) {
|
|
|
|
if (preg_match($this->fieldSpecRegex, $ancFieldSpec)) {
|
|
|
|
if (!@$fields[$ancestor]) {
|
|
|
|
$fields[$ancestor] = array();
|
|
|
|
}
|
|
|
|
$fields[$ancestor][$ancFieldName] = $ancFieldSpec;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-21 04:21:23 +02:00
|
|
|
|
2015-12-17 19:48:37 +01:00
|
|
|
return $fields;
|
|
|
|
}
|
2013-03-09 04:27:18 +01:00
|
|
|
}
|