Created
October 5, 2018 02:22
-
-
Save muskie9/8321b9730c191d5c22b14ce2f316a1af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace Foo\Bar\Baz\Tasks; | |
use SilverStripe\Assets\File; | |
use SilverStripe\Core\ClassInfo; | |
use SilverStripe\Dev\BuildTask; | |
use SilverStripe\Dev\Debug; | |
use SilverStripe\ORM\DataObject; | |
use SilverStripe\ORM\DB; | |
use SilverStripe\Versioned\Versioned; | |
/** | |
* Class ContentFileMigrationTask | |
* @package Foo\Bar\Baz\Tasks | |
*/ | |
class ContentFileMigrationTask extends BuildTask | |
{ | |
/** | |
* @var string | |
*/ | |
protected $title = 'Content File Migration Task'; | |
/** | |
* @var string | |
*/ | |
private static $segment = 'content-file-migration-task'; | |
/** | |
* Mapping property for field updates | |
* | |
* @var array | |
*/ | |
private $mapping = []; | |
/** | |
* @param \SilverStripe\Control\HTTPRequest $request | |
*/ | |
public function run($request) | |
{ | |
$this->setMapping(); | |
$this->migrateContentFiles(); | |
} | |
/** | |
* Migrate file image references to the new SS4 shortcode | |
*/ | |
protected function migrateContentFiles() | |
{ | |
foreach ($this->getMapping() as $class => $tables) { | |
foreach ($tables as $table => $fields) { | |
$selectString = 'ID'; | |
foreach ($fields as $field) { | |
$selectString = "$selectString, \"{$field}\""; | |
} | |
$records = DB::query("SELECT {$selectString} FROM \"{$table}\""); | |
//echo count($records) . " records to be updated in {$table}\n"; | |
foreach ($records as $record) { | |
//echo count($fields) . " field(s) to be updated for {$class} - {$record['ID']}\n"; | |
foreach ($fields as $field) { | |
$this->updateFileReference($class, $table, $record, $field); | |
} | |
} | |
} | |
} | |
} | |
/** | |
* Yield all subclasses of DataObject | |
* | |
* @return \Generator | |
*/ | |
protected function getClasses() | |
{ | |
$classes = ClassInfo::subclassesFor(DataObject::class); | |
unset($classes[strtolower(DataObject::class)]); | |
foreach ($classes as $class) { | |
yield $class; | |
} | |
} | |
/** | |
* Set mapping array | |
* | |
* [ | |
* 'ClassName' => [ | |
* 'TableName' => [ | |
* 'FieldName', | |
* 'FieldName2', | |
* ], | |
* 'TableName2' => [ | |
* 'FieldName3', | |
* ], | |
* ], | |
* ] | |
* | |
* @param $class | |
*/ | |
protected function setMapping() | |
{ | |
foreach ($this->getClasses() as $class) { | |
foreach ($this->getDBFields($class) as $field => $type) { | |
if ($type == 'HTMLText') { | |
$table = $this->getFieldTable($class, $field); | |
if (!isset($this->mapping[$class])) { | |
$this->mapping[$class] = []; | |
} | |
if (!isset($This->mapping[$class][$table])) { | |
$this->mapping[$class][$table] = []; | |
} | |
if (!in_array($field, $this->mapping[$class][$table])) { | |
$this->mapping[$class][$table][] = $field; | |
} | |
} | |
} | |
} | |
return $this; | |
} | |
/** | |
* Get the array of Class, Table and Field mapping for updating | |
* | |
* @return array | |
*/ | |
protected function getMapping() | |
{ | |
if (empty($this->mapping)) { | |
$this->setMapping(); | |
} | |
return $this->mapping; | |
} | |
/** | |
* Get database fields for a given class | |
* | |
* @param $class | |
* @return mixed | |
*/ | |
protected function getDBFields($class) | |
{ | |
return $class::singleton()->getSchema()->fieldSpecs($class); | |
} | |
/** | |
* Get the appropriate table to update via SQL as to not publish draft content from the SS3 site | |
* | |
* @param $class | |
* @param $field | |
* @return mixed | |
*/ | |
protected function getFieldTable($class, $field) | |
{ | |
return $class::singleton()->getSchema()->tableForField($class, $field); | |
} | |
/** | |
* Update records of based on ContentFileMigrationTask::mapping | |
* | |
* @param $class | |
* @param $table | |
* @param $record | |
* @param $field | |
*/ | |
protected function updateFileReference($class, $table, $record, $field) | |
{ | |
if (preg_match('/<img\s*(?:src\s*\=\s*[\'\"](.*?)[\'\"].*?\s*|\s*|\s*)+.*?>/sm', $record[$field], $matches)) { | |
foreach ($matches as $match) { | |
preg_match('/src=".*"/', $match, $source); | |
$path = substr($source[0], 5, strlen($source[0]) - 6); | |
$parts = explode('/', $path); | |
$file = File::get()->filter('FileFilename:PartialMatch', $parts[count($parts) - 1])->first(); | |
$newValue = $this->getNewFieldValue($record, $field, $match, $file); | |
if ($newValue) { | |
$versioned = $class::singleton()->hasExtension(Versioned::class); | |
//echo "{$table}\n"; | |
DB::prepared_query("UPDATE \"{$table}\" SET \"{$field}\" = ? WHERE ID = ?", [$newValue, $record['ID']]); | |
echo "Updated image reference for: {$class} - {$record['ID']}\n"; | |
if ($versioned) { | |
echo "Versioned and live tables updated\n"; | |
DB::prepared_query("UPDATE \"{$table}_Live\" SET \"{$field}\" = ? WHERE ID = ?", [$newValue, $record['ID']]); | |
DB::prepared_query("UPDATE \"{$table}_Versions\" SET \"{$field}\" = ? WHERE RecordID = ?", [$newValue, $record['ID']]); | |
} | |
} else { | |
echo "Couldn't update {$class} = {$record['ID']} - {$match}\n"; | |
} | |
} | |
} | |
} | |
/** | |
* Replace image instances with new shortcode | |
* | |
* @param $record | |
* @param $field | |
* @param $match | |
* @param $file | |
* @return mixed | |
*/ | |
protected function getNewFieldValue($record, $field, $match, $file) | |
{ | |
if ($file instanceof File) { | |
$newPath = $file->getURL(); | |
$find = [ | |
'/<img/', | |
'/src=".*"/', | |
'/>/', | |
]; | |
$replace = [ | |
'[image', | |
"src=\"{$newPath}\"", | |
']', | |
]; | |
$newReference = preg_replace($find, $replace, $match); | |
echo "New image referance {$newReference}\n"; | |
$newValue = str_replace($match, $newReference, $record[$field]); | |
return $newValue; | |
} | |
return false; | |
} | |
} |
Update: My tweaks are not quite ready for prime time. I introduced problems with Fluent and Versions. Will add comment when I think I have them fixed.
Should work better now. Also added file lookup caching for speed.
https://gist.github.com/phil-quinn/aed842994e85fd79bf7efc6aa1c78455
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Thanks for creating this! I forked it and made a few tweaks:
https://gist.github.com/phil-quinn/aed842994e85fd79bf7efc6aa1c78455
Hope this is useful, and thanks again for creating this!