Files
VITEC-website/migrations/fill_test_subsolution.php
orasche 8e67f5db23 Sub-solution workbook pipeline on layout 5, fix element order in both importers
- New, deliberately separate pipeline for sub-solutions (markets and
  solutions must never break each other): generator
  vitec:generate-subsolution-workbooks (list from the page tree below
  /solutions, 39 workbooks, every sub-solution matched to its record),
  SubsolutionWorkbookImporter + CLI vitec:import-subsolution-workbooks,
  and a "Sub-Solutions" tab in the VITEC Import module with its own
  inbox migrations/subsolutions_xlsx_in/
- Targets the existing template 5 "Solution Detail" without changing
  it: hero element in colPos 1, the remaining sections in fixed order in
  colPos 0, found again by CType on re-import; existing empty sub-solution
  pages are switched to layout 5, missing ones created hidden;
  detail_page set on the solution record
- Workbook per the Figma "07 Solution Detail page": hero without video
  teaser, intro with headline and without learn-more/portfolio, extended
  icon list, own page-layout reference image
- Shared content elements: market hero/intro/insights relabelled
  "Market/Solution", market intro gains the optional intro_headline
  field (new column, requires extension:setup)
- Fix: DataHandler puts every NEW record with a positive pid at the top
  of its column, so pages built in one run came out reversed. Both
  importers now track the page order per colPos and write
  tt_content.sorting explicitly after the DataHandler run; re-applying
  repairs pages imported earlier (verified on the control-room
  sub-solution and sub-market page 443)
- migrations/fill_test_subsolution.php: realistic test content from
  vitec.com copy and images for the control-room sub-solution
- Docs section 5z
2026-10-07 15:39:18 +02:00

147 lines
7.4 KiB
PHP

<?php
/**
* Test data for the sub-solution pipeline: fills the generated workbook
* "Control Room Platforms SOC NOC Command Centres" with realistic copy
* (based on vitec.com product content) and real vitec.com images, and
* drops it into the import inbox.
*
* Starts from the FRESH generated file (named ranges intact), never from
* an Excel-saved copy. Stories/products are picked from the workbook's own
* dropdown lists, so every value is a valid DB title.
*
* php migrations/fill_test_subsolution.php
*/
require __DIR__ . '/../vendor/autoload.php';
use PhpOffice\PhpSpreadsheet\IOFactory;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
$source = __DIR__ . '/subsolutions_xlsx_out/Control Room & Command Centre Solutions/Control Room Platforms SOC NOC Command Centres.xlsx';
$target = __DIR__ . '/subsolutions_xlsx_in/Control Room Platforms SOC NOC Command Centres.xlsx';
if (!is_file($source)) {
fwrite(STDERR, "Source workbook not found: $source\n(run vendor/bin/typo3 vitec:generate-subsolution-workbooks first)\n");
exit(1);
}
if (is_file($target)) {
copy($target, $target . '.bak');
echo "Backup of the existing inbox file: " . basename($target) . ".bak\n";
}
$spreadsheet = IOFactory::load($source);
// ---- dropdown lists from the workbook itself ------------------------------
$lists = $spreadsheet->getSheetByName('Lists');
$column = static function (string $col) use ($lists): array {
$values = [];
for ($r = 1; $r <= $lists->getHighestRow(); $r++) {
$v = trim((string)$lists->getCell($col . $r)->getValue());
if ($v !== '') {
$values[] = $v;
}
}
return $values;
};
$stories = $column('A');
$products = $column('B');
/** First list entry matching each keyword, in keyword order, no duplicates. */
$pick = static function (array $list, array $keywords, int $max) : array {
$chosen = [];
foreach ($keywords as $keyword) {
foreach ($list as $entry) {
if (stripos($entry, $keyword) !== false && !in_array($entry, $chosen, true)) {
$chosen[] = $entry;
break;
}
}
if (count($chosen) >= $max) {
break;
}
}
return $chosen;
};
$storyPicks = $pick($stories, ['National Defense', 'Defense Visual', 'ISR Video Mission', 'Disease Control', 'Parliament', 'Police', 'Government'], 3);
$productPicks = $pick($products, ['VSN V3', 'VSNMicro', 'VSNMini', 'Aligo', 'QTX100', 'WallControl', 'Fx4'], 4);
$featured = array_shift($productPicks) ?? '';
// ---- content ----------------------------------------------------------------
$values = [
'hero_subline' => 'Unified, low-latency video visualisation for security, network and command operations - built for 24/7 reliability.',
'hero_cta_label' => 'Talk to an expert',
'hero_cta_url' => '/contact',
'hero_bgimage_url' => 'https://www.vitec.com/fileadmin/user_upload/gov_16-9.jpg',
'intro_headline' => 'Every source, every screen, one operational picture',
'intro_text' => 'Security operations centres, network operations centres and command centres all face the same challenge: operators must see and act on many live sources at once - CCTV, IP streams, dashboards, sensor data and broadcast feeds - without delay and without interruption. VITEC control room platforms bring these sources together on configurable video walls and operator workstations. VSN Series controllers render any mix of HDMI, DisplayPort, SDI and IP inputs, Aligo extends the wall to remote positions with visually lossless 4K and sub-millisecond latency, and WallControl 10 lets operators rearrange layouts in seconds as situations evolve.',
'intro_image_url' => 'https://www.vitec.com/fileadmin/user_upload/control-room_control-launch.png',
'flow_headline' => 'Built for mission-critical operations',
'flow_subtext' => 'VITEC control room platforms are designed for environments where every second counts and downtime is not an option. Key advantages include:',
'flow_card1_icon' => 'capture',
'flow_card1_title' => 'Ingest',
'flow_card1_front' => 'Bring every source onto the wall: HDMI, DisplayPort, SDI and IP streams.',
'flow_card1_back' => 'Vision and ActiveSQX capture cards ingest local and networked sources side by side, so CCTV, PCs, dashboards and broadcast feeds share one display surface.',
'flow_card2_icon' => 'view',
'flow_card2_title' => 'Visualise',
'flow_card2_front' => 'Build any wall layout and change it in seconds with WallControl 10.',
'flow_card2_back' => 'Operators drag and drop sources, recall saved layouts per shift or incident, and scale from a single screen to walls of 24 displays and beyond.',
'flow_card3_icon' => 'distribute',
'flow_card3_title' => 'Extend',
'flow_card3_front' => 'Take the wall to every operator position with Aligo AVoIP.',
'flow_card3_back' => 'Visually lossless 4K60 over 10Gb networks with sub-millisecond latency, plus KVM control of remote sources - ideal for supervisor desks and overflow rooms.',
'flow_card4_icon' => 'respond',
'flow_card4_title' => 'Stay resilient',
'flow_card4_front' => 'Rack-mounted VSN V3 controllers with dual-redundant power for 24/7 duty.',
'flow_card4_back' => 'Hardware-based rendering keeps playback smooth and synchronised, while redundant power supplies keep the picture up when it matters most.',
'testi_headline' => 'Trusted in control rooms worldwide',
'prod_featured' => $featured,
'insights_text1' => 'Modern control rooms are moving from fixed matrix switching to flexible, IP-based visualisation - for faster situational awareness, simpler expansion and lower operating costs.',
'insights_text2' => 'See how organisations in defense, government and critical infrastructure use VITEC technology to keep operators informed and in control:',
'insights_cta_label' => 'Explore success stories',
'insights_cta_target' => '/success-stories',
'seo_title' => 'Control Room Platforms for SOC, NOC & Command Centres | VITEC',
'seo_description' => 'Unify CCTV, IP streams and data on resilient video walls: VITEC VSN controllers, Aligo AVoIP and WallControl 10 for SOC, NOC and command centres.',
];
foreach ($storyPicks as $i => $story) {
$values['testi_story_' . ($i + 1)] = $story;
}
foreach ($productPicks as $i => $product) {
$values['prod_card_' . ($i + 1)] = $product;
}
// ---- write via named ranges -------------------------------------------------
$missing = [];
foreach ($values as $name => $value) {
$range = $spreadsheet->getNamedRange($name);
if ($range === null || $range->getWorksheet() === null) {
$missing[] = $name;
continue;
}
$cell = str_replace('$', '', (string)$range->getValue());
$cell = str_contains($cell, '!') ? substr($cell, strpos($cell, '!') + 1) : $cell;
$range->getWorksheet()->getCell($cell)->setValue($value);
}
@mkdir(dirname($target), 0775, true);
(new Xlsx($spreadsheet))->save($target);
$spreadsheet->disconnectWorksheets();
@chmod($target, 0664);
echo "Written: " . $target . "\n";
echo "Featured product: " . ($featured !== '' ? $featured : '(none found!)') . "\n";
echo "Product cards: " . ($productPicks !== [] ? implode(' | ', $productPicks) : '(none found)') . "\n";
echo "Case studies: " . ($storyPicks !== [] ? implode(' | ', $storyPicks) : '(none found)') . "\n";
if ($missing !== []) {
echo "WARNING - named ranges not found: " . implode(', ', $missing) . "\n";
}