Skip to content

Instantly share code, notes, and snippets.

@lukasdoerr
Last active September 4, 2023 07:42
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lukasdoerr/e63b04f5df5e409ebde8e6866b0a3ca4 to your computer and use it in GitHub Desktop.
Save lukasdoerr/e63b04f5df5e409ebde8e6866b0a3ca4 to your computer and use it in GitHub Desktop.
TYPO3 Flux to Not Flux Migrator
<?php
/*
MIT License with Attribution Clause
Copyright (c) 2023 Lukas Dörr
Permission is hereby granted to use, modify, and distribute this software, provided that:
1. The above copyright notice and this permission notice are included.
2. Attribution to Lukas Doerr and link to www.ldoerr.com are prominently displayed.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
*/
if (!ini_get('display_errors')) {
ini_set('display_errors', '1');
}
$config = array(
'DB' => [
'Connections' => [
'Default' => [
'charset' => 'utf8mb4',
'dbname' => '',
'driver' => 'mysqli',
'host' => 'localhost',
'password' => '',
'socket' => '',
'user' => '',
],
],
],
);
$con = mysqli_connect(
$config['DB']['Connections']['Default']['host'],
$config['DB']['Connections']['Default']['user'],
$config['DB']['Connections']['Default']['password'],
$config['DB']['Connections']['Default']['dbname'],
);
if(!@$con) {
die('db con failed');
}
else {
if(!@isset($_GET['do'])) {
?>
<html>
<h1 style="font-family: Arial, Helvetica, sans-serif;">
<span style="color:red;">F</span>
<span style="color:orange;">l</span>
<span style="color:yellow;">u</span>
<span style="color:green;">x</span>
<span style="color:blue;">M</span>
<span style="color:indigo;">i</span>
<span style="color:purple;">g</span>
<span style="color:red;">r</span>
<span style="color:orange;">a</span>
<span style="color:yellow;">t</span>
<span style="color:green;">o</span>
<span style="color:blue;">r</span>
</h1>
<a href="fluxmigrator.php?do=element_migrator">Migrate Content Elements</a>
<br>
<a href="fluxmigrator.php?do=page_migrator">Migrate Pages</a>
</html>
<?php
}
else {
switch ($_GET['do']) {
case 'page_migrator':
//Get Pages and their flux_grid Information
$getPagesText = "SELECT * FROM pages WHERE deleted = 0";
$getPagesQuery = mysqli_query($con, $getPagesText);
$foundFluxLayouts = [];
$foundFluxLayoutsSub = [];
while ($pages = mysqli_fetch_array($getPagesQuery)) {
if(isset($pages['tx_fed_page_controller_action']) || isset($pages['tx_fed_page_controller_action_sub'])) {
//Layouts
if(!in_array($pages['tx_fed_page_controller_action'], $foundFluxLayouts) && !empty($pages['tx_fed_page_controller_action'])) {
$foundFluxLayouts[] = $pages['tx_fed_page_controller_action'];
}
//Layouts for subpages
if(!in_array($pages['tx_fed_page_controller_action_sub'], $foundFluxLayoutsSub) && !empty($pages['tx_fed_page_controller_action_sub'])) {
$foundFluxLayoutsSub[] = $pages['tx_fed_page_controller_action_sub'];
}
}
}
if(count($foundFluxLayouts)) {
?>
<h2>Flux Page Migrator</h2>
Remember to add the affected backend_layouts before proceeding<br>
And Backup your pages table before running the queries<br>
<h3>Found Flux Layouts:</h3>
<?php
foreach($foundFluxLayouts as $layout) {
echo '<br>'.$layout;
}
echo "<br><br>";
foreach($foundFluxLayouts as $layout) {
//echo '<br>'.$layout.'<br>';
$migrLayout = strstr($layout, '>');
$migrLayout = trim($migrLayout,'>');
echo "UPDATE pages SET backend_layout = 'pagets__$migrLayout' WHERE tx_fed_page_controller_action = '$layout' AND deleted = 0;<br>";
}
echo "<br><hr><br>
<h3>Found Flux Sub-Layouts:</h3>";
foreach($foundFluxLayoutsSub as $layout) {
echo '<br>'.$layout;
}
echo "<br><br>";
foreach($foundFluxLayoutsSub as $layout) {
$migrLayout = strstr($layout, '>');
$migrLayout = trim($migrLayout,'>');
echo "UPDATE pages SET backend_layout_next_level = 'pagets__$migrLayout' WHERE tx_fed_page_controller_action_sub = '$layout' AND deleted = 0;<br>";
}
?>
</form>
<?php
}
else {
echo "Pages not found.";
}
break;
case 'element_migrator':
?>
<h2>Flux Content Element Migrator</h2>
<form action="fluxmigrator.php?do=get_element" method="post">
<label for="ctype_flux">CType of Flux Element:</label><br>
<input required type="text" name="ctype_flux"/>
<br><br>
<input type="submit" value="Check">
</form>
<?php
break;
case 'get_element':
$cTypeFlux = mysqli_real_escape_string($con, $_POST['ctype_flux']);
$textGetFluxElements = "SELECT * FROM tt_content WHERE CType LIKE '%".$cTypeFlux."%' AND deleted = 0";
$foundFluxElements = [];
if($queryGetFluxElements = mysqli_query($con, $textGetFluxElements)) {
while($faFluxElements = mysqli_fetch_array($queryGetFluxElements)) {
$foundFluxElements[] = $faFluxElements;
}
}
//Check if element is in use and not deleted
if(@count($foundFluxElements)) {
$availableFields = [];
$d = false;
foreach($foundFluxElements as $element) {
if(!$d) {
$xml = simplexml_load_string($element['pi_flexform']);
$json = json_encode($xml);
$flexFormConfiguration = json_decode($json,TRUE);
/*
echo "flexFormConfiguration:<br><pre>";
print_r($flexFormConfiguration);
echo "</pre><br>";
*/
if(@is_array($flexFormConfiguration['data']['sheet']['language']['field']))
{
$fields = $flexFormConfiguration['data']['sheet']['language']['field'];
}
if(@count($fields)) {
foreach ($fields as $field) {
if(isset($field['@attributes']['index'])) {
if(!in_array($field['@attributes']['index'], $availableFields)) {
$availableFields[] = $field['@attributes']['index'];
}
}
else {
//Try to find without @attributes
if(isset($fields['index'])) {
if(!in_array($fields['index'], $availableFields)) {
$availableFields[] = $fields['index'];
}
}
else {
//die('no fields found');
}
}
}
}
}
//$d = true;
}
// echo "available fields:<br><pre>";
// print_r($availableFields);
// echo "</pre><br>";
?>
<form action="fluxmigrator.php?do=generate_queries" method="post">
<?php
foreach($availableFields as $field) {
echo '
<div class="form-group">
<label for="'.$field.'">Mask Fieldname to migrate "'.$field.'" to:</label><br>
<input id="'.$field.'" type="text" name="fields['.$field.']"> is FAL? <input type="checkbox" name="fields_fal['.$field.']" /> yes
<br>
</div>
';
}
?>
<div class="form-group">
<br>
<label for="from_flux">CType of Flux Element:</label><br>
<input id="from_flux" type="text" name="from_flux" value="<?php echo $cTypeFlux; ?>" readonly/>
<br><br>
</div>
<div class="form-group">
<label for="mask_element">Mask Element CType (begins with mask_*, like: "mask_exampleelement"):</label><br>
<input required type="text" name="mask_ctype"/>
<br><br>
</div>
<input type="submit" value="Generate Query">
</form>
<?php
}
else {
echo $cTypeFlux." not found, maybe already migrated?";
}
break;
case 'generate_queries':
$cTypeFlux = mysqli_real_escape_string($con, $_POST['from_flux']);
$cTypeMask = mysqli_real_escape_string($con, $_POST['mask_ctype']);
$fluxFields = $_POST['fields'];
if(@isset($_POST['fields_fal'])) {
$fluxFALFields = $_POST['fields_fal'];
}
else {
$fluxFALFields = NULL;
}
//Get Flux Elements again:
$textGetFluxElements = "SELECT * FROM tt_content WHERE CType LIKE '%".$cTypeFlux."%' AND deleted = 0";
$FALqueries = [];
if($queryGetFluxElements = mysqli_query($con, $textGetFluxElements)) {
while($faFluxElements = mysqli_fetch_array($queryGetFluxElements)) {
//Get Element Flux Settings again:
$xml = simplexml_load_string($faFluxElements['pi_flexform']);
$json = json_encode($xml);
$flexFormConfiguration = json_decode($json,TRUE);
if(@is_array($flexFormConfiguration['data']['sheet']['language']['field']))
{
$fields = $flexFormConfiguration['data']['sheet']['language']['field'];
}
//echo "<br>Fields: <br><pre>".print_r($fields)."</pre><br><br>";
$queryMigration = "UPDATE tt_content SET CType = '".$cTypeMask."'";
$queryMigrationFAL = "UPDATE sys_file_reference SET tablenames = 'tt_content'";
$availableFields = [];
$c = 0;
if(@count($fields)) {
foreach ($fields as $field) {
//print_are($field, 'flexFormConfiguration', true);
if(isset($field['@attributes']['index'])) {
$availableFields[$c]['name'] = $field['@attributes']['index'];
if(is_array($field['value'])) {
$availableFields[$c]['value'] = 'NULL';
}
else {
$availableFields[$c]['value'] = htmlspecialchars($field['value']);
}
}
else {
//Try to find without @attributes
if(isset($field['index'])) {
$availableFields[$c]['name'] = $field['index'];
}
else {
//$availableFields[$c]['name'] = $field['index'];
if(is_array($fields['value'])) {
$availableFields[$c]['value'] = 'NULL';
}
else {
$availableFields[$c]['value'] = htmlspecialchars($fields['value']);
}
}
}
$c++;
}
}
// echo "availableFields:<br><pre>";
// print_r($availableFields);
// echo "</pre>";
//Add the available fields:
foreach ($availableFields as $avField) {
if($avField['value'] == 'NULL') {
$queryMigration .= ", ".$fluxFields[$avField['name']]." = ''";
}
else {
$queryMigration .= ", ".$fluxFields[$avField['name']]." = '".$avField['value']."'";
}
if(isset($fluxFALFields)) {
if(@$fluxFALFields[$avField['name']] == 'on') {
$queryMigrationFAL .= ", fieldname = '".$fluxFields[$avField['name']]."'";
}
}
}
$queryMigrationFAL .= " WHERE uid_foreign = '".$faFluxElements['uid']."' AND deleted = 0;";
$FALqueries[] = $queryMigrationFAL;
$queryMigration .= " WHERE uid = '".$faFluxElements['uid']."';<br>";
//Check if there are FAL selected Fields to switch File Reference!
echo $queryMigration.'<br>';
unset($availableFields);
}
echo "<hr><br><br>FAL Queries for selected fields:<br><br>";
foreach ($FALqueries as $query) {
echo "<br>".$query;
}
}
break;
default:
throw new \Exception('Unexpected value');
}
}
mysqli_close($con);
}
function print_are($obj, $title = false, $collapse = false) {
$template = '
<style>
.print_are,
.print_are * {
box-sizing: border-box;
padding: 0;
margin: 0;
min-height: 0;
height: auto;
font-family: monospace;
line-height: normal;
}
.print_are {
display: block;
position: relative;
width: 100%;
padding: 10px;
}
.print_are .pre-wrap {
background-color: white;
color: black;
border: 1px solid #333;
border-radius: 2px;
box-shadow: 0 0 5px #aaa;
font-size: 14px;
line-height: 16px;
position: relative;
text-align: left;
overflow: auto;
display: block;
}
.print_are .pre-header {
padding: 10px 10px 9px;
border-bottom: 1px solid #333;
}
.print_are .pre-obj-type,
.print_are .pre-actions a {
font-size: 16px;
font-weight: bold;
}
.print_are .pre-actions a {
text-decoration: none;
font-weight: normal;
font-size: 14px;
}
.print_are .pre-actions a:hover {
text-decoration: underline;
}
.print_are .pre-actions {
float: right;
}
.print_are .pre-content {
padding: 0;
margin: 0;
overflow: auto;
background: #fff;
border: none;
border-radius: 0;
box-shadow: none;
}
.print_are .pre-line,
.print_are .pre-lines,
.print_are .pre-content {
font-size: 12px;
line-height: normal;
}
.print_are .pre-lines {
min-height: 20px;
}
.print_are .pre-lines[data-lines-count="1"] > li:empty::after {
content: "(Empty)";
color: #aaa;
letter-spacing: 1px;
}
.print_are .pre-toggle-wrap .unwrap > span {
display: none;
}
.print_are .wrap-lines .pre-toggle-wrap .unwrap > span {
display: inline;
}
.print_are .wrap-lines .pre-content .pre-line {
white-space: pre-wrap;
}
.print_are .pre-lines {
display: block;
background: #f2f2f2;
border-left: 1px solid #333;
padding: 2px 0;
}
.print_are .pre-line {
padding: 2px 0 2px 4px;
}
.print_are .pre-line .key {
cursor: pointer;
}
.print_are .pre-line.selected,
.print_are .pre-line:hover {
background: #eec;
font-weight: bold;
}
.print_are .pre-line.selected {
box-shadow: 0 0 0 1px #ccc inset;
margin: 1px;
}
</style>
<div class="print_are">
<div class="pre-wrap">
<div class="pre-header">
<span class="pre-obj-type">{obj_type}</span>
<div class="pre-actions">
<a href="#" class="pre-toggle-wrap" onclick="Print_Are.TW(this, event);" title="Wrap/Unwrap Long Lines"><span class="unwrap"><span>UN-</span>WRAP</span></a>
/
<a href="#" class="pre-toggle-display" onclick="Print_Are.TD(this, event);" title="Show/Hide {obj_type}">{toggle_display_text}</a>
<div style="clear:both"></div>
</div>
</div>
<div style="clear:both"></div>
<pre class="pre-content" style="padding-left: {padding_left}px; display: {obj_hide};"><ol class="pre-lines" data-lines-count="{lines_count}"><li class="pre-line" onclick="Print_Are.TB(this)">{obj_content}</li></ol></pre>
</div>
</div>
<script>
if (typeof Print_Are !== "object") {
var Print_Are = new Object;
// Toggle Display
Print_Are.TD = function(el, event) {
event.preventDefault();
var e = el.parentElement.parentElement.parentElement;
var p = e.querySelector(".pre-content");
if (p !== null) {
if (p.style.display === "none") {
el.innerHTML = "CLOSE";
p.style.display = "block";
} else {
el.innerHTML = "OPEN";
p.style.display = "none";
}
}
}
// Toggle Wrap
Print_Are.TW = function(el, event) {
event.preventDefault();
var e = el.parentElement.parentElement.parentElement;
if (e !== null) {
var c = e.classList.contains("wrap-lines");
if (c) {
e.classList.remove("wrap-lines");
} else {
e.classList.add("wrap-lines");
}
}
}
// Toggle Bookmark
Print_Are.TB = function(el) {
el.classList.toggle("selected");
}
// Select Text
Print_Are.ST = function(el) {
el.parentElement.classList.add("selected");
var range = document.createRange();
var selection = window.getSelection();
selection.removeAllRanges();
range.selectNodeContents(el);
selection.addRange(range);
}
}
</script>';
$obj_type = gettype($obj);
$obj_type = $title ? "$obj_type - $title" : $obj_type;
$obj_str = print_r($obj, true);
//$obj_str = str_replace(" ", " ", $obj_str); // tabsize = 2
preg_match_all("/\[[^\]]*\]/", $obj_str, $matches);
if( count($matches[0]) > 0 ) {
$vars = array();
foreach ($matches[0] as $match) {
$val = str_replace(array('[',']'), '', $match);
$vars["$match"] = "[<span class='key' title='Click to select text.' onclick='Print_Are.ST(this)'>$val</span>]";
}
$search = array_keys($vars);
$replace = array_values($vars);
$obj_str = str_replace($search, $replace, $obj_str);
}
$obj_arr = explode(PHP_EOL, $obj_str);
$lines_count = count($obj_arr);
$obj_content = implode("</li><li class='pre-line' onclick='Print_Are.TB(this)'>", $obj_arr);
$obj_hide = $collapse ? 'none' : 'block';
$toggle_display_text = $collapse ? 'OPEN' : 'CLOSE';
$default_padding_left = 15;
$padding_offset = 10;
$line_count = (string) count($obj_arr);
$count_length = (int) strlen($line_count);
$padding_left = $default_padding_left + ($count_length * $padding_offset);
$vars = array(
'{lines_count}' => $lines_count,
'{obj_hide}' => $obj_hide,
'{obj_type}' => $obj_type,
'{obj_content}' => $obj_content,
'{padding_left}' => $padding_left,
'{toggle_display_text}' => $toggle_display_text,
);
$search = array_keys($vars);
$replace = array_values($vars);
$output = str_replace($search, $replace, $template);
echo $output;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment