mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 01:25:55 +02:00
Added an export function to attachment_types admin pages.
This commit is contained in:
parent
09eb3c226a
commit
091311cdf1
6 changed files with 199 additions and 20 deletions
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue