I have set up this form with the intention of when I add details into the; title, description and emotion text fields and then press submit, this data will be stored as xml in the php file.
I am struggling to set up the controller so that when I submit the form it actually stores this data. The example that I will provide below worked previously when I was storing it on my database, but I am now wanting to store it as xml.
Projects Controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Orchestra\Parser\Xml\Facade as XmlParser;
interface OutputType
{
public function generate();
}
//project class has been imported
use App\Project;
class ProjectsController extends Controller
{
public function index()
{
//because the class has been imported we can reference it like this rather than '\App\Project::all();'
$projects = Project::all();
//passing the JSON to the view
return view ('projects.index', ['projects'=> $projects]); //can also use 'compact('projects') instead of the ['projects'=> $projects]
}
//new method called create
public function create()
{
return view ('projects.create');
}
//new method called store
public function store()
{
if (isset($_POST['submit'])) {
$xmlType = new XMLType();
$xmlType->createParent('programme', ['id' => 1])
->addElement('name', $_POST['name'], ['type' => 'string'])
->addElement('description', $_POST['description'])
->addElement('mood', $_POST['mood'])
->groupParentAndElements()
->createParent('others', ['id' => 2, 'attr' => 'ex'])
->addElement('example', 'A value here')
->groupParentAndElements();
//whenever you wish to output
$xmlType->generate();
}
return view('projects.upload');
}
//changed this from upload to show
public function upload()
{
return view('projects.upload');
}
//changed this from upload to show
public function show()
{
return view ('projects.upload', compact('user'));
}
public function slider()
{
return view ('projects.upload', compact('user'));
}
}
Database.php (where I want to store submitted data as xml
<?
$xmlstr = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<programmeList>
<programme id="1">
<name>School of Rock</name>
<image>images/schoolofrock.jpg</image>
<description>After being kicked out of a rock band, Dewey Finn becomes a substitute teacher </description>
<mood>Agitated</mood>
</programme>
<programme id="2">
<name>Pitch Perfect 2</name>
<image>images/pitchperfect2.jpg</image>
<description>After a humiliating command performance at The Kennedy Center, the Barden Bellas enter an international competition that no American group has ever won in order to regain their status and right to perform.</description>
<mood>Fearless</mood>
</programme>
</programmeList>
XML;
?>
Create.php (view)
<link rel="stylesheet" href="CSS/app.css" type="text/css">
<meta name = "viewport" content="width = device-width, initial-scale = 1">
<link rel = "stylesheet" href = "https://www.w3schools.com. /lib/w3.css">
<!DOCTYPE html>
<html>
<head>
<title>Upload</title>
</head>
<body>
<!-- Sky logo + Sky cinema logo -->
<div class="box">
<td style="text-align:center;color:black;font-size:50px;">
<img src="/images/sky.png" title="Sky" alt="Sky" width="auto" height="125" />
</td>
<td style="text-align: right;position: relative; color:black;font-size:50px;">
<img src="/images/sky_cinema.png" title="sky_cinema" alt="Sky" width="auto" height="125" />
</td>
</div>
<div>
<ul class="w3-navbar w3-black">
<li><a href="/projects/upload">Moodslider Home</a></li>
<li><a href="/projects/create">Upload Content</a></li>
</ul>
</div>
<div>
<h1>Upload a movie</h1>
</div>
<!--post request followed by an action which states where the data will be posted/returned -->
<form method="POST" action="/projects">
<form action="/projects/upload" method="post" enctype="multipart/form-data">
{{ @csrf_field() }}
<h4>Movie Title</h4><input type="text" name="name">
<br/>
<h4>Movie Description</h4><textarea name="description" rows="5" cols="50" wrap="physical">
</textarea>
<h4>Movie Emotion</h4>
<input type="radio" name="mood" value="Agitated">Agitated<br>
<input type="radio" name="mood" value="Calm">Calm<br>
<input type="radio" name="mood" value="Happy">Happy<br>
<input type="radio" name="mood" value="Sad">Sad<br>
<input type="radio" name="mood" value="Tired">Tired<br>
<input type="radio" name="mood" value="WideAwake">Wide Awake<br>
<input type="radio" name="mood" value="Scared">Scared<br>
<input type="radio" name="mood" value="Fearless">Fearless<br>
<br/>
Choose a file to upload: <input type="file" name="fileToUpload" id="fileToUpload" />
<br/>
<br/>
<input type="submit" value="submit" name="submit" />
</form>
</form>
</body>
</html>
XMLType
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
//import the interface above
class XMLType implements OutputType
{
protected $xml;
protected $parentElement;
protected $elementGroup;
public function __construct()
{
$this->xml= new \DOMDocument('1.0', 'ISO-8859-15');
}
public function createParent($type, $attributes = [])
{
$this->parentElement = $this->xml->createElement($type);
$this->addAttributes($this->parentElement, $attributes);
return $this;
}
private function addAttributes(&$element, $attributes)
{
if (sizeof($attributes) > 0) {
foreach($attributes as $type => $value) {
$element->setAttribute($type, $value);
}
}
}
public function addElement($type, $element, $attributes = [])
{
$this->elementGroup = $this->xml->createElement($type, $element);
$this->addAttributes($this->elementGroup, $attributes);
return $this;
}
public function groupParentAndElements()
{
$this->parentElement->appendChild($this->elementGroup);
return $this;
}
public function generate()
{
$this->xml->appendChild($this->parentElement);
print $this->xml->saveXML(); //here I am saving and printing but you can change to suit your needs. It is at this point it is ready to generate the XML
}
}
I would look at using SQLite to store the data as a second DB connection
Alternatively you would need to use something like SimpleXML grab the contents of the file, add or modify the contents and then save it back to the file.
http://php.net/manual/en/book.simplexml.php
This would all need to go in your store method and would not allow you to use the Projects model
Hope this helps
Interface
interface OutputType
{
public function generate();
}
XMLFile Class
//import the interface above
class XMLType implements OutputType
{
protected $xml;
protected $parentElement;
protected $elementGroup;
protected $parentList = [];
protected $elementList = [];
public function __construct()
{
$this->xml= new \DOMDocument('1.0', 'ISO-8859-15');
}
public function createParent($type, $attributes = [])
{
$this->parentElement = $this->xml->createElement($type);
$this->addAttributes($this->parentElement, $attributes);
return $this;
}
private function addAttributes(&$element, $attributes)
{
if (sizeof($attributes) > 0) {
foreach($attributes as $type => $value) {
$element->setAttribute($type, $value);
}
}
}
public function addElement($type, $element, $attributes = [])
{
$this->elementGroup = $this->xml->createElement($type, $element);
$this->addAttributes($this->elementGroup, $attributes);
$this->elementList[] = $this->elementGroup;
return $this;
}
/**
* We wish to trigger this every time you want to ad d a new parent to
* hold new elements! So the program knows to close
* the previous one before starting a new and mesh all into one single
* element, which we do not want to!
**/
public function groupParentAndElements()
{
foreach($this->elementList as $prevElements) {
$this->parentElement->appendChild($prevElements);
}
$this->parentList[] = $this->parentElement;
$this->elementList = [];
return $this;
}
public function generate()
{
//Uses filled parentList where each parent contains its child elements to generate the XML
foreach ($this->parentList as $prevParent) {
$this->xml->appendChild($prevParent);
}
//here I am saving and printing but you can change to suit your needs.
//It is at this point it is ready to generate the XML
print $this->xml->saveXML();
}
}
Where you wish to use the XML class
if (isset($_POST['submit'])) {
$xmlType = new XMLType();
$xmlType->createParent('programme', ['id' => 1])
->addElement('name', $_POST['name'], ['type' => 'string'])
->addElement('description', $_POST['description'])
->addElement('mood', $_POST['mood'])
->groupParentAndElements()
->createParent('others', ['id' => 2, 'attr' => 'ex'])
->addElement('example', 'A value here')
->groupParentAndElements();
//whenever you wish to output
$xmlType->generate();
}
Output
<programme id="1">
<name type="string">
//your post name
</name>
<description>
//your post description
</description>
<mood>
//your post mood
</mood>
</programme>
<others id="2" attr="ex">
<example>
A value here
</example>
</others>
To the class you can always add extra elements like notes, types etc, it will be up to your XML needs. Just need to follow the structure or even go further :)
Storing the XML content into a file
interface FileCreationContract
{
public function create($content);
}
class XMLFile implements FileCreationContract
{
const REGEX_EXTENTION_LOOKOUT = '/\.[^.]+$/';
const EXTENTION = '.xml';
protected $path;
protected $filename;
public function __construct ($filename, $path = '')
{
$this->filename = $filename;
$this->parseFilename();
if (empty($this->path)) {
$this->path = realpath(__DIR__);
}
}
/**
* If programmer mistakes and adds extention, removes it to make sure the wrong extention was not added;
*/
private function parseFilename()
{
if ( strpos($this->filename, self::EXTENTION) === FALSE ) {
$this->filename = preg_replace(self::REGEX_EXTENTION_LOOKOUT, '', $this->filename) . self::EXTENTION;
}
if (empty($this->filename)) {
$this->filename = 'default-name'.self::EXTENTION;
}
}
/**
* @return mixed
*/
public function getPath ()
{
return $this->path;
}
/**
* @param mixed $path
*
* @return XMLFile
*/
public function setPath ($path)
{
$this->path = $path;
return $this;
}
/**
* @return mixed
*/
public function getFilename ()
{
return $this->filename;
}
/**
* @param mixed $filename
*
* @return XMLFile
*/
public function setFilename ($filename)
{
$this->filename = $filename;
$this->parseFilename();
return $this;
}
public function create ($content)
{
$file = fopen($this->path.$this->filename, 'w') or die("Unable too open file!"); //I recommend throwing an exception here!
fwrite($file, $content);
fclose($file);
}
}
At your controller, after constructing the XML Content
...
$xmlFile = new XMLFile('database.php', 'path/to/your/public/folder/');
$xmlFile->create($xmlType->generate());
...
NOTE: Replace print
to return
on your generate()
method from XMLType
class
This new class wil make sure your filename follows the expected .xml
format for saving. You can always override the path to save the file at constructor level or call ->setPath('new/path/');
to replace it, before you call create()
;