Added an export function to attachment_types admin pages.

This commit is contained in:
Jan Böhmer 2019-04-07 19:30:42 +02:00
parent 09eb3c226a
commit 091311cdf1
6 changed files with 199 additions and 20 deletions

View file

@ -33,11 +33,16 @@ namespace App\Controller;
use App\Entity\AttachmentType;
use App\Entity\StructuralDBElement;
use App\Form\BaseEntityAdminForm;
use App\Form\ExportType;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\ResponseHeaderBag;
use Symfony\Component\Routing\Annotation\Route;
use Symfony\Component\Serializer\SerializerInterface;
/**
* @Route("/attachment_type")
@ -119,4 +124,91 @@ class AttachmentTypeController extends AbstractController
return $this->redirectToRoute('attachment_type_new');
}
/**
* @Route("/export")
* @param Request $request
* @param SerializerInterface $serializer
* @param EntityManagerInterface $em
* @return Response
*/
public function exportAll(Request $request, SerializerInterface $serializer, EntityManagerInterface $em)
{
$entities = $em->getRepository(AttachmentType::class)->findAll();
return $this->exportHelper($entities, $request, $serializer);
}
/**
* @Route("/{id}/export", name="attachment_type_export")
* @param Request $request
* @param AttachmentType $entity
*/
public function exportEntity(Request $request, AttachmentType $entity, SerializerInterface $serializer)
{
return $this->exportHelper($entity, $request, $serializer);
}
protected function exportHelper($entity, Request $request, SerializerInterface $serializer) : Response
{
$format = $request->get('format') ?? "json";
//Check if we have one of the supported formats
if (!in_array($format, ['json', 'csv', 'yaml', 'xml'])) {
throw new \InvalidArgumentException("Given format is not supported!");
}
//Check export verbosity level
$level = $request->get('level') ?? 'extended';
if (!in_array($level, ['simple', 'extended', 'full'])) {
throw new \InvalidArgumentException('Given level is not supported!');
}
//Check for include children option
$include_children = $request->get('include_children') ?? false;
//Check which groups we need to export, based on level and include_children
$groups = array($level);
if ($include_children) {
$groups[] = 'include_children';
}
//Plain text should work for all types
$content_type = "text/plain";
//Try to use better content types based on the format
switch ($format) {
case 'xml':
$content_type = "application/xml";
break;
case 'json':
$content_type = "application/json";
break;
}
$response = new Response($serializer->serialize($entity, $format,
[
'groups' => $groups,
'as_collection' => true,
'csv_delimiter' => ';', //Better for Excel
'xml_root_node_name' => 'PartDBExport'
]));
$response->headers->set('Content-Type', $content_type);
//If view option is not specified, then download the file.
if (!$request->get('view')) {
$filename = "export_" . $entity->getName() . "_" . $level . "." . $format;
// Create the disposition of the file
$disposition = $response->headers->makeDisposition(
ResponseHeaderBag::DISPOSITION_ATTACHMENT,
$filename
);
// Set the content disposition
$response->headers->set('Content-Disposition', $disposition);
}
return $response;
}
}

View file

@ -77,7 +77,6 @@ class AttachmentType extends StructuralDBElement
*/
public function getIDString(): string
{
return '';
//return 'AT' . sprintf('%09d', $this->getID());
return 'AT' . sprintf('%09d', $this->getID());
}
}

View file

@ -24,6 +24,8 @@ declare(strict_types=1);
namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* This class is for managing all database objects.
@ -36,6 +38,23 @@ use Doctrine\ORM\Mapping as ORM;
* @ORM\MappedSuperclass()
*
* @ORM\EntityListeners({"App\Security\EntityListeners\ElementPermissionListener"})
*
* @DiscriminatorMap(typeProperty="type", mapping={
* "attachment_type" = "App\Entity\AttachmentType",
* "attachment" = "App\Entity\Attachment",
* "category" = "App\Entity\Attachment",
* "device" = "App\Entity\Device",
* "device_part" = "App\Entity\DevicePart",
* "footprint" = "App\Entity\Footprint",
* "group" = "App\Entity\Group",
* "manufacturer" = "App\Entity\Manufacturer",
* "orderdetail" = "App\Entity\Orderdetail",
* "part" = "App\Entity\Part",
* "pricedetail" = "App\Entity\Pricedetail",
* "storelocation" = "App\Entity\Storelocation",
* "supplier" = "App\Entity\Supplier",
* "user" = "App\Entity\User"
* })
*/
abstract class DBElement
{
@ -43,6 +62,7 @@ abstract class DBElement
* @ORM\Column(type="integer")
* @ORM\Id()
* @ORM\GeneratedValue()
* @Groups({"full"})
*/
protected $id;
@ -64,6 +84,7 @@ abstract class DBElement
* This should have a form like P000014, for a part with ID 14.
*
* @return string The ID as a string;
*
*/
abstract public function getIDString(): string;

View file

@ -25,6 +25,7 @@ namespace App\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* All subclasses of this class have an attribute "name".
@ -38,18 +39,21 @@ abstract class NamedDBElement extends DBElement
* @var string The name of this element.
* @ORM\Column(type="string")
* @Assert\NotBlank()
* @Groups({"simple", "extended", "full"})
*/
protected $name = '';
/**
* @var \DateTime The date when this element was modified the last time.
* @ORM\Column(type="datetimetz", name="last_modified")
* @Groups({"extended", "full"})
*/
protected $lastModified;
/**
* @var \DateTime The date when this element was created.
* @ORM\Column(type="datetimetz", name="datetime_added")
* @Groups({"extended", "full"})
*/
protected $addedDate;

View file

@ -27,6 +27,8 @@ use Doctrine\ORM\Mapping as ORM;
use Doctrine\ORM\PersistentCollection;
use App\Validator\Constraints\NoneOfItsChildren;
use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
use Symfony\Component\Serializer\Annotation\DiscriminatorMap;
use Symfony\Component\Serializer\Annotation\Groups;
/**
* All elements with the fields "id", "name" and "parent_id" (at least).
@ -52,17 +54,20 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
// subclasses
/**
* @var StructuralDBElement[]
* @Groups({"include_children"})
*/
protected $children;
/**
* @var StructuralDBElement
* @NoneOfItsChildren()
* @Groups({"include_parents"})
*/
protected $parent;
/**
* @var string The comment info for this element
* @ORM\Column(type="string", nullable=true)
* @Groups({"simple", "extended", "full"})
*/
protected $comment;
@ -78,7 +83,9 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
protected $level = 0;
/** @var string[] all names of all parent elements as a array of strings,
* the last array element is the name of the element itself */
* the last array element is the name of the element itself
*
*/
private $full_path_strings;
/******************************************************************************
@ -154,24 +161,25 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
/**
* Get the level.
*
* The level of the root node is -1.
* The level of the root node is -1.
*
* @return int the level of this element (zero means a most top element
* [a subelement of the root node])
*
*/
public function getLevel(): int
{
if (0 === $this->level) {
/**
* Only check for nodes that have a parent. In the other cases zero is correct.
*/
if (0 === $this->level && $this->parent !== null) {
$element = $this->parent;
$parent_id = $element->getParentID();
while ($parent_id > 0) {
while ($element !== null) {
/** @var StructuralDBElement $element */
$element = $element->parent;
$parent_id = $element->getParentID();
++$this->level;
}
}
return $this->level;
}
@ -181,6 +189,7 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
* @param string $delimeter the delimeter of the returned string
*
* @return string the full path (incl. the name of this element), delimeted by $delimeter
*
*/
public function getFullPath(string $delimeter = self::PATH_DELIMITER_ARROW): string
{
@ -216,6 +225,11 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
return $this->children;
}
public function getChildren(): PersistentCollection
{
return $this->children;
}
/******************************************************************************
*
* Setters

View file

@ -29,8 +29,6 @@
<div class="col-8">
{{ form_start(form) }}
<fieldset>
<legend>
{% if entity.ID %}
@ -43,14 +41,26 @@
<ul class="nav nav-tabs mt-2">
<li class="nav-item"><a class="link-anchor active nav-link" data-toggle="tab" href="#home">standard.label</a></li>
<li class="nav-item"><a data-toggle="tab" class="link-anchor nav-link" href="#info">infos.label</a></li>
{% if entity.id %}
<li class="nav-item"><a data-toggle="tab" class="link-anchor nav-link" href="#export">export.label</a> </li>
{% endif %}
</ul>
<div class="tab-content mb-3 mt-3">
<div id="home" class="tab-pane fade show active">
{{ form_start(form) }}
{{ form_row(form.name) }}
{{ form_row(form.parent) }}
{% block additional_controls %}{% endblock %}
{{ form_row(form.comment) }}
{{ form_row(form.save) }}
{{ form_row(form.reset) }}
{{ form_end(form) }}
{# Only include on existing parts #}
{% if entity.id %}
{{ include('AdminPages/_delete_form.html.twig') }}
{% endif %}
</div>
<div id="info" class="tab-pane fade">
@ -87,20 +97,59 @@
</div>
</div>
</div>
{% if entity.id %}
<div id="export" class="tab-pane fade">
<form class="form-horizontal" data-no-ajax method="post" action="{{ path('attachment_type_export', {'id': entity.id}) }}">
<div class="form-row">
<label class="col-form-label col-md-2">{% trans %}export.format{% endtrans %}</label>
<div class="col">
<select class="form-control" name="format">
<option value="json">JSON</option>
<option value="xml">XML</option>
<option value="csv">CSV</option>
<option value="yaml">YAML</option>
</select>
</div>
</div>
<div class="form-row mt-2">
<label class="col-form-label col-md-2">{% trans %}export.level{% endtrans %}</label>
<div class="col">
<select class="form-control" name="level">
<option value="simple">{% trans %}export.level.simple{% endtrans %}</option>
<option value="extended" selected>{% trans %}export.level.extended{% endtrans %}</option>
<option value="full">{% trans %}export.level.full{% endtrans %}</option>
</select>
</div>
</div>
<div class="form-row mt-2">
<div class="offset-2 col">
<div class="form-check abc-checkbox">
<input class="form-check-input" name="include_children" id="include_children" type="checkbox" checked>
<label class="form-check-label" for="include_children">
{% trans %}export.include_children{% endtrans %}
</label>
</div>
</div>
</div>
<div class="form-row mt-2">
<div class="offset-2 col">
<button type="submit" class="btn btn-primary">{% trans %}export.btn{% endtrans %}</button>
</div>
</div>
</form>
</div>
{% endif %}
</div>
{{ form_row(form.save) }}
{{ form_row(form.reset) }}
</fieldset>
{{ form_end(form) }}
{# Only include on existing parts #}
{% if entity.id %}
{{ include('AdminPages/_delete_form.html.twig') }}
{% endif %}
</div>
</div>