Is it possible fetching data from a cached xml file and then showing them on front end?
I was thinking doing it in a TYPO3 extension and with its domain model (and getter/setter) but without a database table. And then filling in data with SimpleXML just to "store" them in memory. At least display the data from domain model with fluid on front end. But I don't know is this approach right or is there a better way to do that? In particular setting up the persistence layer I don't understand.
For any help I thank you very much for your effort in advance.
I found an "acceptable" solution. My approach for that was:
1. Get all items from xml file
Controller: listAction, detailAction
public function listAction() {
$jobs = $this->xmlDataRepository->findAll();
$jobsArray = $this->simpleXmlObjToArr($jobs);
$jobsArraySorted = $this->sortJobsByTitle($jobsArray);
$this->view->assign('jobs', $jobsArraySorted);
}
public function detailAction($slugid) {
$job = $this->xmlDataRepository->findBySlugWithId($slugid);
$this->view->assign('job', $job[0]);
}
Repository: findAll, findBySlugWithId
public function findAll() {
$objectStorage = new ObjectStorage();
$dataFolder = ConfigurationService::setDataFolder();
$xmlFile = glob($dataFolder . '*.xml')[0];
$xmlData = simplexml_load_file($xmlFile,'SimpleXMLElement',LIBXML_NOWARNING);
// error handling
if ($xmlData === false) {
...
}
foreach($xmlData->children() as $job) {
$objectStorage->attach($job);
}
return $objectStorage;
}
public function findBySlugWithId($slugid) {
// get id from slugid
$id = substr($slugid,strrpos($slugid,'-',-1)+1);
$objectStorage = new ObjectStorage();
$dataFolder = ConfigurationService::setDataFolder();
$xmlFile = glob($dataFolder . '*.xml')[0];
$xmlData = simplexml_load_file($xmlFile,'SimpleXMLElement',LIBXML_NOWARNING);
// error handling
if ($xmlData === false) {
...
}
$jobfound = false;
foreach($xmlData->children() as $job) {
if ($job->JobId == $id) {
$objectStorage->attach($job);
$jobfound = true;
}
}
// throw 404-error
if (!$jobfound) {
$response = GeneralUtility::makeInstance(ErrorController::class)->pageNotFoundAction(
$GLOBALS['TYPO3_REQUEST'],
'Ihre angeforderte Seite wurde nicht gefunden',
['code' => PageAccessFailureReasons::PAGE_NOT_FOUND]
);
throw new ImmediateResponseException($response, 9000006460);
}
return $objectStorage;
}
2. Add a slug field (controller)
protected function simpleXmlObjToArr($obj) {
// 2-dimensional array
$array = [];
foreach($obj as $item){
$row = [];
foreach($item as $key => $val){
$row[(string)$key] = (string)$val;
}
//add slug field, build it with Title
$row['Slug'] = $this->convertToPathSegment($row['Titel']);
// add $row to $array
array_push($array,$row);
}
return $array;
}
3. Sort the items (controller)
protected function sortJobsByTitle(array $jobs) {
$title = array();
$id = array();
foreach ($jobs as $key => $job) {
$title[$key] = $job['Titel'];
$id[$key] = $job['JobId'];
}
// sort jobs array according to title, uid (uid because if there are courses with the same title!)
array_multisort($title,SORT_ASC, $id,SORT_ASC, $jobs,SORT_STRING);
return $jobs;
}
4. Display sorted items on the front end (templates)
List.html:
...
<ul>
<f:for each="{jobs}" as="job">
<li>
<f:comment>
<f:link.action class="" pageUid="2" action="show" arguments="{id: job.JobId, slug: job.Slug}">{job.Titel}</f:link.action> ({job.JobId})<br>
<f:link.action class="" pageUid="2" action="detail" arguments="{xml: job}">NEW {job.Titel}</f:link.action> ({job.JobId})
</f:comment>
<f:variable name="slugid" value="{job.Slug}-{job.JobId}"/>
<f:link.action class="" pageUid="2" action="detail" arguments="{slugid: slugid}"><f:format.raw>{job.Titel}</f:format.raw></f:link.action> ({job.JobId})
</li>
</f:for>
</ul>
...
Detail.html:
...
<f:image src="{job.Grafik}" width="500" alt="Detailstellenbild" />
<p><strong><f:format.raw>{job.Titel}</f:format.raw></strong> ({job.JobId})</p>
<p>Region: {job.Region}</p>
<f:format.html>{job.Beschreibung}</f:format.html>
...
5. Create unique pretty url
...
routeEnhancers:
XmlJobDetail:
type: Extbase
limitToPages:
- 2
extension: Wtdisplayxmldata
plugin: Displayxmldata
routes:
-
routePath: '/{job-slugid}'
_controller: 'XmlData::detail'
_arguments:
job-slugid: slugid
defaultController: 'XmlData::list'
aspects:
job-slugid:
type: XmlDetailMapper
Routing/Aspect/XmlDetailMapper.php:
use TYPO3\CMS\Core\Routing\Aspect\StaticMappableAspectInterface;
use TYPO3\CMS\Extbase\Utility\DebuggerUtility;
class XmlDetailMapper implements StaticMappableAspectInterface {
/**
* {@inheritdoc}
*/
public function generate(string $value): ?string
{
return $value !== false ? (string)$value : null;
}
/**
* {@inheritdoc}
*/
public function resolve(string $value): ?string
{
return isset($value) ? (string)$value : null;
}
}