mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2025-06-21 09:35:49 +02:00
Added a basic dialog for editing/creating attachmentType elements.
This commit is contained in:
parent
4652339879
commit
3e7150735d
12 changed files with 568 additions and 146 deletions
|
@ -68,8 +68,12 @@ class AjaxUI {
|
||||||
* Starts the ajax ui und execute handlers registered in addStartAction().
|
* Starts the ajax ui und execute handlers registered in addStartAction().
|
||||||
* Should be called in a document.ready, after handlers are set.
|
* Should be called in a document.ready, after handlers are set.
|
||||||
*/
|
*/
|
||||||
public start()
|
public start(disabled : boolean = false)
|
||||||
{
|
{
|
||||||
|
if(disabled) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
console.info("AjaxUI started!");
|
console.info("AjaxUI started!");
|
||||||
|
|
||||||
this.BASE = $("body").data("base-url") + "/";
|
this.BASE = $("body").data("base-url") + "/";
|
||||||
|
@ -227,6 +231,19 @@ class AjaxUI {
|
||||||
{
|
{
|
||||||
let options : JQueryFormOptions = {
|
let options : JQueryFormOptions = {
|
||||||
success: this.onAjaxComplete,
|
success: this.onAjaxComplete,
|
||||||
|
beforeSerialize: function() : boolean {
|
||||||
|
|
||||||
|
//Update the content of textarea fields using CKEDITOR before submitting.
|
||||||
|
|
||||||
|
//@ts-ignore
|
||||||
|
for(let name in CKEDITOR.instances)
|
||||||
|
{
|
||||||
|
//@ts-ignore
|
||||||
|
CKEDITOR.instances[name].updateElement();
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
},
|
||||||
beforeSubmit: function (arr, $form, options) : boolean {
|
beforeSubmit: function (arr, $form, options) : boolean {
|
||||||
//When data-with-progbar is specified, then show progressbar.
|
//When data-with-progbar is specified, then show progressbar.
|
||||||
if($form.data("with-progbar") != undefined) {
|
if($form.data("with-progbar") != undefined) {
|
||||||
|
|
97
src/Controller/AttachmentTypeController.php
Normal file
97
src/Controller/AttachmentTypeController.php
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* part-db version 0.1
|
||||||
|
* Copyright (C) 2005 Christoph Lechner
|
||||||
|
* http://www.cl-projects.de/
|
||||||
|
*
|
||||||
|
* part-db version 0.2+
|
||||||
|
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
|
||||||
|
* http://code.google.com/p/part-db/
|
||||||
|
*
|
||||||
|
* Part-DB Version 0.4+
|
||||||
|
* Copyright (C) 2016 - 2019 Jan Böhmer
|
||||||
|
* https://github.com/jbtronics
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Controller;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\AttachmentType;
|
||||||
|
use App\Form\BaseEntityAdminForm;
|
||||||
|
use Doctrine\ORM\EntityManagerInterface;
|
||||||
|
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
|
||||||
|
use Symfony\Component\HttpFoundation\Request;
|
||||||
|
use Symfony\Component\Routing\Annotation\Route;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/attachment_type")
|
||||||
|
* @package App\Controller
|
||||||
|
*/
|
||||||
|
class AttachmentTypeController extends AbstractController
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* @Route("/{id}/edit", requirements={"id"="\d+"}, name="attachment_type_edit")
|
||||||
|
* @Route("/{id}/", requirements={"id"="\d+"})
|
||||||
|
*/
|
||||||
|
public function edit(AttachmentType $entity, Request $request, EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
|
||||||
|
$form = $this->createForm(BaseEntityAdminForm::class, $entity);
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$em->persist($entity);
|
||||||
|
$em->flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('AdminPages/AttachmentTypeAdmin.html.twig', [
|
||||||
|
'entity' => $entity,
|
||||||
|
'form' => $form->createView()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Route("/new")
|
||||||
|
*
|
||||||
|
* @return \Symfony\Component\HttpFoundation\Response
|
||||||
|
*/
|
||||||
|
public function new(Request $request, EntityManagerInterface $em)
|
||||||
|
{
|
||||||
|
$new_entity = new AttachmentType();
|
||||||
|
|
||||||
|
$this->denyAccessUnlessGranted('create', $new_entity);
|
||||||
|
|
||||||
|
$form = $this->createForm(BaseEntityAdminForm::class, $new_entity);
|
||||||
|
|
||||||
|
$form->handleRequest($request);
|
||||||
|
|
||||||
|
if ($form->isSubmitted() && $form->isValid()) {
|
||||||
|
$em->persist($new_entity);
|
||||||
|
$em->flush();
|
||||||
|
//$this->addFlash('success', $translator->trans('part.created_flash'));
|
||||||
|
|
||||||
|
return $this->redirectToRoute('attachment_type_edit', ['id' => $new_entity->getID()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->render('AdminPages/AttachmentTypeAdmin.html.twig', [
|
||||||
|
'entity' => $new_entity,
|
||||||
|
'form' => $form->createView()
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
|
@ -23,6 +23,7 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
|
use App\Validator\Constraints\NoneOfItsChildren;
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
use Doctrine\Common\Collections\ArrayCollection;
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
|
|
||||||
|
|
|
@ -50,9 +50,11 @@ abstract class DBElement
|
||||||
* Get the ID. The ID can be zero, or even negative (for virtual elements). If an elemenent is virtual, can be
|
* Get the ID. The ID can be zero, or even negative (for virtual elements). If an elemenent is virtual, can be
|
||||||
* checked with isVirtualElement().
|
* checked with isVirtualElement().
|
||||||
*
|
*
|
||||||
* @return int the ID of this element
|
* Returns null, if the element is not saved to the DB yet.
|
||||||
|
*
|
||||||
|
* @return int|null the ID of this element
|
||||||
*/
|
*/
|
||||||
final public function getID(): int
|
final public function getID(): ?int
|
||||||
{
|
{
|
||||||
return (int) $this->id;
|
return (int) $this->id;
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,20 +74,22 @@ abstract class NamedDBElement extends DBElement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the last time when the element was modified.
|
* Returns the last time when the element was modified.
|
||||||
|
* Returns null if the element was not yet saved to DB yet.
|
||||||
*
|
*
|
||||||
* @return \DateTime The time of the last edit.
|
* @return \DateTime|null The time of the last edit.
|
||||||
*/
|
*/
|
||||||
public function getLastModified(): \DateTime
|
public function getLastModified(): ?\DateTime
|
||||||
{
|
{
|
||||||
return $this->lastModified;
|
return $this->lastModified;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the date/time when the element was created.
|
* Returns the date/time when the element was created.
|
||||||
|
* Returns null if the element was not yet saved to DB yet.
|
||||||
*
|
*
|
||||||
* @return \DateTime The creation time of the part.
|
* @return \DateTime|null The creation time of the part.
|
||||||
*/
|
*/
|
||||||
public function getAddedDate(): \DateTime
|
public function getAddedDate(): ?\DateTime
|
||||||
{
|
{
|
||||||
return $this->addedDate;
|
return $this->addedDate;
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,9 +23,9 @@ declare(strict_types=1);
|
||||||
|
|
||||||
namespace App\Entity;
|
namespace App\Entity;
|
||||||
|
|
||||||
use Doctrine\Common\Collections\ArrayCollection;
|
|
||||||
use Doctrine\ORM\Mapping as ORM;
|
use Doctrine\ORM\Mapping as ORM;
|
||||||
use Doctrine\ORM\PersistentCollection;
|
use Doctrine\ORM\PersistentCollection;
|
||||||
|
use App\Validator\Constraints\NoneOfItsChildren;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All elements with the fields "id", "name" and "parent_id" (at least).
|
* All elements with the fields "id", "name" and "parent_id" (at least).
|
||||||
|
@ -53,6 +53,7 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
protected $children;
|
protected $children;
|
||||||
/**
|
/**
|
||||||
* @var StructuralDBElement
|
* @var StructuralDBElement
|
||||||
|
* @NoneOfItsChildren()
|
||||||
*/
|
*/
|
||||||
protected $parent;
|
protected $parent;
|
||||||
|
|
||||||
|
@ -97,10 +98,10 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
|
|
||||||
//Check if both elements compared, are from the same type:
|
//Check if both elements compared, are from the same type:
|
||||||
if ($class_name != \get_class($another_element)) {
|
if ($class_name != \get_class($another_element)) {
|
||||||
throw new \InvalidArgumentException('isChildOf() funktioniert nur mit Elementen des gleichen Typs!');
|
throw new \InvalidArgumentException('isChildOf() only works for objects of the same type!');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (null == $this->getID()) { // this is the root node
|
if (null == $this->getParent()) { // this is the root node
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -116,13 +117,13 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Get the parent-ID
|
* Get the parent-ID
|
||||||
*
|
*
|
||||||
* @retval integer * the ID of the parent element
|
* @return integer * the ID of the parent element
|
||||||
* * NULL means, the parent is the root node
|
* * NULL means, the parent is the root node
|
||||||
* * the parent ID of the root node is -1
|
* * the parent ID of the root node is -1
|
||||||
*/
|
*/
|
||||||
public function getParentID(): int
|
protected function getParentID(): int
|
||||||
{
|
{
|
||||||
return $this->parent_id ?? self::ID_ROOT_ELEMENT; //Null means root element
|
return $this->parent_id ?? self::ID_ROOT_ELEMENT; //Null means root element
|
||||||
}
|
}
|
||||||
|
@ -139,14 +140,12 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the comment of the element.
|
* Get the comment of the element.
|
||||||
*
|
|
||||||
* @param bool $parse_bbcode Should BBCode converted to HTML, before returning
|
|
||||||
*
|
|
||||||
* @return string the comment
|
* @return string the comment
|
||||||
*/
|
*/
|
||||||
public function getComment(bool $parse_bbcode = true): string
|
public function getComment(): ?string
|
||||||
{
|
{
|
||||||
return htmlspecialchars($this->comment ?? '');
|
return $this->comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -179,8 +178,6 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
* @param string $delimeter the delimeter of the returned string
|
* @param string $delimeter the delimeter of the returned string
|
||||||
*
|
*
|
||||||
* @return string the full path (incl. the name of this element), delimeted by $delimeter
|
* @return string the full path (incl. the name of this element), delimeted by $delimeter
|
||||||
*
|
|
||||||
* @throws Exception if there was an error
|
|
||||||
*/
|
*/
|
||||||
public function getFullPath(string $delimeter = self::PATH_DELIMITER_ARROW): string
|
public function getFullPath(string $delimeter = self::PATH_DELIMITER_ARROW): string
|
||||||
{
|
{
|
||||||
|
@ -189,9 +186,13 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
$this->full_path_strings[] = $this->getName();
|
$this->full_path_strings[] = $this->getName();
|
||||||
$element = $this;
|
$element = $this;
|
||||||
|
|
||||||
while (null != $element->parent) {
|
$overflow = 20; //We only allow 20 levels depth
|
||||||
|
|
||||||
|
while (null != $element->parent && $overflow >= 0) {
|
||||||
$element = $element->parent;
|
$element = $element->parent;
|
||||||
$this->full_path_strings[] = $element->getName();
|
$this->full_path_strings[] = $element->getName();
|
||||||
|
//Decrement to prevent mem overflow.
|
||||||
|
$overflow--;
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->full_path_strings = array_reverse($this->full_path_strings);
|
$this->full_path_strings = array_reverse($this->full_path_strings);
|
||||||
|
@ -219,143 +220,31 @@ abstract class StructuralDBElement extends AttachmentContainingDBElement
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Change the parent ID of this element.
|
* Sets the new parent object
|
||||||
*
|
* @param self $new_parent The new parent object
|
||||||
* @param int|null $new_parent_id * the ID of the new parent element
|
* @return StructuralDBElement
|
||||||
* * NULL if the parent should be the root node
|
|
||||||
*/
|
*/
|
||||||
public function setParentID($new_parent_id): self
|
public function setParent(?self $new_parent) : self
|
||||||
{
|
{
|
||||||
$this->parent_id = $new_parent_id;
|
/*
|
||||||
|
if ($new_parent->isChildOf($this)) {
|
||||||
|
throw new \InvalidArgumentException('You can not use one of the element childs as parent!');
|
||||||
|
} */
|
||||||
|
|
||||||
|
$this->parent = $new_parent;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the comment.
|
* Set the comment.
|
||||||
*
|
|
||||||
* @param string $new_comment the new comment
|
* @param string $new_comment the new comment
|
||||||
*
|
* @return StructuralDBElement
|
||||||
* @throws Exception if there was an error
|
|
||||||
*/
|
*/
|
||||||
public function setComment(string $new_comment): self
|
public function setComment(?string $new_comment): self
|
||||||
{
|
{
|
||||||
$this->comment = $new_comment;
|
$this->comment = $new_comment;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/********************************************************************************
|
|
||||||
*
|
|
||||||
* Tree / Table Builders
|
|
||||||
*
|
|
||||||
*********************************************************************************/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Build a HTML tree with all subcategories of this element.
|
|
||||||
*
|
|
||||||
* This method prints a <option>-Line for every item.
|
|
||||||
* <b>The <select>-tags are not printed here, you have to print them yourself!</b>
|
|
||||||
* Deeper levels have more spaces in front.
|
|
||||||
*
|
|
||||||
* @param int $selected_id the ID of the selected item
|
|
||||||
* @param bool $recursive if true, the tree will be recursive
|
|
||||||
* @param bool $show_root if true, the root node will be displayed
|
|
||||||
* @param string $root_name if the root node is the very root element, you can set its name here
|
|
||||||
* @param string $value_prefix This string is used as a prefix before the id in the value part of the option.
|
|
||||||
*
|
|
||||||
* @return string HTML string if success
|
|
||||||
*
|
|
||||||
* @throws Exception if there was an error
|
|
||||||
*/
|
|
||||||
public function buildHtmlTree(
|
|
||||||
$selected_id = null,
|
|
||||||
bool $recursive = true,
|
|
||||||
bool $show_root = true,
|
|
||||||
string $root_name = '$$',
|
|
||||||
string $value_prefix = ''
|
|
||||||
): string {
|
|
||||||
if ('$$' == $root_name) {
|
|
||||||
$root_name = _('Oberste Ebene');
|
|
||||||
}
|
|
||||||
|
|
||||||
$html = array();
|
|
||||||
|
|
||||||
if ($show_root) {
|
|
||||||
$root_level = $this->getLevel();
|
|
||||||
if ($this->getID() > 0) {
|
|
||||||
$root_name = htmlspecialchars($this->getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
$html[] = '<option value="'.$value_prefix.$this->getID().'">'.$root_name.'</option>';
|
|
||||||
} else {
|
|
||||||
$root_level = $this->getLevel() + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get all subelements
|
|
||||||
$subelements = $this->getSubelements($recursive);
|
|
||||||
|
|
||||||
foreach ($subelements as $element) {
|
|
||||||
$level = $element->getLevel() - $root_level;
|
|
||||||
$selected = ($element->getID() == $selected_id) ? 'selected' : '';
|
|
||||||
|
|
||||||
$html[] = '<option '.$selected.' value="'.$value_prefix.$element->getID().'">';
|
|
||||||
for ($i = 0; $i < $level; ++$i) {
|
|
||||||
$html[] = ' ';
|
|
||||||
}
|
|
||||||
$html[] = htmlspecialchars($element->getName()).'</option>';
|
|
||||||
}
|
|
||||||
|
|
||||||
return implode("\n", $html);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a template loop for a Breadcrumb bar, representing the structural DB element.
|
|
||||||
*
|
|
||||||
* @param $page string The base page, to which the breadcrumb links should be directing to.
|
|
||||||
* @param $parameter string The parameter, which selects the ID of the StructuralDBElement.
|
|
||||||
* @param bool $show_root Show the root as its own breadcrumb.
|
|
||||||
* @param string $root_name The label which should be used for the root breadcrumb.
|
|
||||||
*
|
|
||||||
* @return array An Loop containing multiple arrays, which contains href and caption for the breadcrumb.
|
|
||||||
*/
|
|
||||||
public function buildBreadcrumbLoop(string $page, string $parameter, bool $show_root = false, $root_name = '$$', bool $element_is_link = false): array
|
|
||||||
{
|
|
||||||
$breadcrumb = array();
|
|
||||||
|
|
||||||
if ('$$' == $root_name) {
|
|
||||||
$root_name = _('Oberste Ebene');
|
|
||||||
}
|
|
||||||
|
|
||||||
if ($show_root) {
|
|
||||||
$breadcrumb[] = array('label' => $root_name,
|
|
||||||
'disabled' => true, );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!$this->current_user->canDo(static::getPermissionName(), StructuralPermission::READ)) {
|
|
||||||
return array('label' => '???',
|
|
||||||
'disabled' => true, );
|
|
||||||
}
|
|
||||||
|
|
||||||
$tmp = array();
|
|
||||||
|
|
||||||
if ($element_is_link) {
|
|
||||||
$tmp[] = array('label' => $this->getName(), 'href' => $page.'?'.$parameter.'='.$this->getID(), 'selected' => true);
|
|
||||||
} else {
|
|
||||||
$tmp[] = array('label' => $this->getName(), 'selected' => true);
|
|
||||||
}
|
|
||||||
|
|
||||||
$parent_id = $this->getParentID();
|
|
||||||
while ($parent_id > 0) {
|
|
||||||
/** @var StructuralDBElement $element */
|
|
||||||
$element = static::getInstance($this->database, $this->current_user, $this->log, $parent_id);
|
|
||||||
$parent_id = $element->getParentID();
|
|
||||||
$tmp[] = array('label' => $element->getName(), 'href' => $page.'?'.$parameter.'='.$element->getID());
|
|
||||||
}
|
|
||||||
$tmp = array_reverse($tmp);
|
|
||||||
|
|
||||||
$breadcrumb = array_merge($breadcrumb, $tmp);
|
|
||||||
|
|
||||||
return $breadcrumb;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
76
src/Form/BaseEntityAdminForm.php
Normal file
76
src/Form/BaseEntityAdminForm.php
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* part-db version 0.1
|
||||||
|
* Copyright (C) 2005 Christoph Lechner
|
||||||
|
* http://www.cl-projects.de/
|
||||||
|
*
|
||||||
|
* part-db version 0.2+
|
||||||
|
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
|
||||||
|
* http://code.google.com/p/part-db/
|
||||||
|
*
|
||||||
|
* Part-DB Version 0.4+
|
||||||
|
* Copyright (C) 2016 - 2019 Jan Böhmer
|
||||||
|
* https://github.com/jbtronics
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Form;
|
||||||
|
|
||||||
|
|
||||||
|
use FOS\CKEditorBundle\Form\Type\CKEditorType;
|
||||||
|
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\ResetType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Security\Core\Security;
|
||||||
|
|
||||||
|
class BaseEntityAdminForm extends AbstractType
|
||||||
|
{
|
||||||
|
|
||||||
|
protected $security;
|
||||||
|
|
||||||
|
public function __construct(Security $security)
|
||||||
|
{
|
||||||
|
$this->security = $security;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options)
|
||||||
|
{
|
||||||
|
$entity = $options['data'];
|
||||||
|
|
||||||
|
$builder
|
||||||
|
->add('name', TextType::class, ['empty_data' => '', 'label' => 'name.label',
|
||||||
|
'attr' => ['placeholder' => 'part.name.placeholder'],
|
||||||
|
'disabled' => !$this->security->isGranted('edit', $entity), ])
|
||||||
|
|
||||||
|
->add('parent', EntityType::class, ['class' => get_class($entity), 'choice_label' => 'full_path',
|
||||||
|
'attr' => ['class' => 'selectpicker', 'data-live-search' => true], 'required' => false, 'label' => 'parent.label',
|
||||||
|
'disabled' => !$this->security->isGranted('move', $entity), ])
|
||||||
|
|
||||||
|
->add('comment', CKEditorType::class, ['required' => false,
|
||||||
|
'label' => 'comment.label', 'attr' => ['rows' => 4], 'help' => 'bbcode.hint',
|
||||||
|
'disabled' => !$this->security->isGranted('edit', $entity)])
|
||||||
|
|
||||||
|
//Buttons
|
||||||
|
->add('save', SubmitType::class, ['label' => 'part.edit.save'])
|
||||||
|
->add('reset', ResetType::class, ['label' => 'part.edit.reset']);
|
||||||
|
}
|
||||||
|
}
|
109
src/Security/Voter/StructureVoter.php
Normal file
109
src/Security/Voter/StructureVoter.php
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* part-db version 0.1
|
||||||
|
* Copyright (C) 2005 Christoph Lechner
|
||||||
|
* http://www.cl-projects.de/
|
||||||
|
*
|
||||||
|
* part-db version 0.2+
|
||||||
|
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
|
||||||
|
* http://code.google.com/p/part-db/
|
||||||
|
*
|
||||||
|
* Part-DB Version 0.4+
|
||||||
|
* Copyright (C) 2016 - 2019 Jan Böhmer
|
||||||
|
* https://github.com/jbtronics
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Security\Voter;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\AttachmentType;
|
||||||
|
use App\Entity\Category;
|
||||||
|
use App\Entity\Device;
|
||||||
|
use App\Entity\Footprint;
|
||||||
|
use App\Entity\Manufacturer;
|
||||||
|
use App\Entity\Storelocation;
|
||||||
|
use App\Entity\Supplier;
|
||||||
|
use App\Entity\User;
|
||||||
|
|
||||||
|
class StructureVoter extends ExtendedVoter
|
||||||
|
{
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determines if the attribute and subject are supported by this voter.
|
||||||
|
*
|
||||||
|
* @param string $attribute An attribute
|
||||||
|
* @param mixed $subject The subject to secure, e.g. an object the user wants to access or any other PHP type
|
||||||
|
*
|
||||||
|
* @return bool True if the attribute and subject are supported, false otherwise
|
||||||
|
*/
|
||||||
|
protected function supports($attribute, $subject)
|
||||||
|
{
|
||||||
|
$permission_name = $this->instanceToPermissionName($subject);
|
||||||
|
//If permission name is null, then the subject is not supported
|
||||||
|
return ($permission_name !== null) && $this->resolver->isValidOperation($permission_name, $attribute);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps a instance type to the permission name.
|
||||||
|
* @param $subject mixed The subject for which the permission name should be generated.
|
||||||
|
* @return string|null The name of the permission for the subject's type or null, if the subject is not supported.
|
||||||
|
*/
|
||||||
|
protected function instanceToPermissionName($subject) : ?string
|
||||||
|
{
|
||||||
|
$class_name = get_class($subject);
|
||||||
|
switch ($class_name) {
|
||||||
|
case AttachmentType::class:
|
||||||
|
return 'attachment_types';
|
||||||
|
case Category::class:
|
||||||
|
return 'categories';
|
||||||
|
case Device::class:
|
||||||
|
return 'devices';
|
||||||
|
case Footprint::class:
|
||||||
|
return 'footprints';
|
||||||
|
case Manufacturer::class:
|
||||||
|
return 'manufacturers';
|
||||||
|
case Storelocation::class:
|
||||||
|
return 'storelocations';
|
||||||
|
case Supplier::class:
|
||||||
|
return 'suppliers';
|
||||||
|
}
|
||||||
|
//When the class is not supported by this class return null
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Similar to voteOnAttribute, but checking for the anonymous user is already done.
|
||||||
|
* The current user (or the anonymous user) is passed by $user.
|
||||||
|
*
|
||||||
|
* @param $attribute
|
||||||
|
* @param $subject
|
||||||
|
* @param User $user
|
||||||
|
*
|
||||||
|
* @return bool
|
||||||
|
*/
|
||||||
|
protected function voteOnUser($attribute, $subject, User $user): bool
|
||||||
|
{
|
||||||
|
$permission_name = $this->instanceToPermissionName($subject);
|
||||||
|
//Just resolve the permission
|
||||||
|
return $this->resolver->inherit($user, $permission_name, $attribute) ?? false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
54
src/Validator/Constraints/NoneOfItsChildren.php
Normal file
54
src/Validator/Constraints/NoneOfItsChildren.php
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* part-db version 0.1
|
||||||
|
* Copyright (C) 2005 Christoph Lechner
|
||||||
|
* http://www.cl-projects.de/
|
||||||
|
*
|
||||||
|
* part-db version 0.2+
|
||||||
|
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
|
||||||
|
* http://code.google.com/p/part-db/
|
||||||
|
*
|
||||||
|
* Part-DB Version 0.4+
|
||||||
|
* Copyright (C) 2016 - 2019 Jan Böhmer
|
||||||
|
* https://github.com/jbtronics
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints;
|
||||||
|
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constraints the parent property on StructuralDBElement objects in the way, that neither the object self or any
|
||||||
|
* of its children can be assigned.
|
||||||
|
*
|
||||||
|
* @Annotation
|
||||||
|
* @package App\Validator\Constraints
|
||||||
|
*/
|
||||||
|
class NoneOfItsChildren extends Constraint
|
||||||
|
{
|
||||||
|
/** @var string The message used if it is tried to assign a object as its own parent */
|
||||||
|
public $self_message = 'validator.noneofitschild.self';
|
||||||
|
/** @var string The message used if it is tried to use one of the children for as parent */
|
||||||
|
public $children_message = 'validator.noneofitschild.children';
|
||||||
|
|
||||||
|
public function validatedBy()
|
||||||
|
{
|
||||||
|
return parent::validatedBy(); // TODO: Change the autogenerated stub
|
||||||
|
}
|
||||||
|
}
|
88
src/Validator/Constraints/NoneOfItsChildrenValidator.php
Normal file
88
src/Validator/Constraints/NoneOfItsChildrenValidator.php
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
<?php
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* part-db version 0.1
|
||||||
|
* Copyright (C) 2005 Christoph Lechner
|
||||||
|
* http://www.cl-projects.de/
|
||||||
|
*
|
||||||
|
* part-db version 0.2+
|
||||||
|
* Copyright (C) 2009 K. Jacobs and others (see authors.php)
|
||||||
|
* http://code.google.com/p/part-db/
|
||||||
|
*
|
||||||
|
* Part-DB Version 0.4+
|
||||||
|
* Copyright (C) 2016 - 2019 Jan Böhmer
|
||||||
|
* https://github.com/jbtronics
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace App\Validator\Constraints;
|
||||||
|
|
||||||
|
|
||||||
|
use App\Entity\StructuralDBElement;
|
||||||
|
use Symfony\Bundle\MakerBundle\Str;
|
||||||
|
use Symfony\Component\Form\Exception\UnexpectedTypeException;
|
||||||
|
use Symfony\Component\Validator\Constraint;
|
||||||
|
use Symfony\Component\Validator\ConstraintValidator;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The validator for the NoneOfItsChildren annotation.
|
||||||
|
* @package App\Validator\Constraints
|
||||||
|
*/
|
||||||
|
class NoneOfItsChildrenValidator extends ConstraintValidator
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Checks if the passed value is valid.
|
||||||
|
*
|
||||||
|
* @param mixed $value The value that should be validated
|
||||||
|
* @param Constraint $constraint The constraint for the validation
|
||||||
|
*/
|
||||||
|
public function validate($value, Constraint $constraint)
|
||||||
|
{
|
||||||
|
if (!$constraint instanceof NoneOfItsChildren) {
|
||||||
|
throw new UnexpectedTypeException($constraint, NoneOfItsChildren::class);
|
||||||
|
}
|
||||||
|
|
||||||
|
// custom constraints should ignore null and empty values to allow
|
||||||
|
// other constraints (NotBlank, NotNull, etc.) take care of that
|
||||||
|
if (null === $value || '' === $value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Check if the object is assigned to itself
|
||||||
|
/** @var StructuralDBElement $entity */
|
||||||
|
$entity = $this->context->getObject();
|
||||||
|
/** @var StructuralDBElement $value */
|
||||||
|
|
||||||
|
// Check if the targeted parent is the object itself:
|
||||||
|
$entity_id = $entity->getID();
|
||||||
|
if ($entity_id !== null && $entity_id === $value->getID()) {
|
||||||
|
//Set the entity to a valid state
|
||||||
|
$entity->setParent(null);
|
||||||
|
$this->context->buildViolation($constraint->self_message)->addViolation();
|
||||||
|
//The other things can not happen.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the targeted parent is a child object
|
||||||
|
if ($value->isChildOf($entity)) {
|
||||||
|
//Set the entity to a valid state
|
||||||
|
$entity->setParent(null);
|
||||||
|
$this->context->buildViolation($constraint->children_message)->addViolation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
5
templates/AdminPages/AttachmentTypeAdmin.html.twig
Normal file
5
templates/AdminPages/AttachmentTypeAdmin.html.twig
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
{% extends "AdminPages/EntityAdminBase.html.twig" %}
|
||||||
|
|
||||||
|
{% block card_title %}
|
||||||
|
<i class="fas fa-file-alt fa-fw"></i> {% trans %}attachment_type.caption{% endtrans %}
|
||||||
|
{% endblock %}
|
82
templates/AdminPages/EntityAdminBase.html.twig
Normal file
82
templates/AdminPages/EntityAdminBase.html.twig
Normal file
|
@ -0,0 +1,82 @@
|
||||||
|
{% extends "main_card.html.twig" %}
|
||||||
|
|
||||||
|
{% block card_content %}
|
||||||
|
<div class="row">
|
||||||
|
<div class="col-4">
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="col-8">
|
||||||
|
|
||||||
|
{{ form_start(form) }}
|
||||||
|
|
||||||
|
<fieldset>
|
||||||
|
<legend>
|
||||||
|
{% if entity.ID %}
|
||||||
|
<strong>{% trans with {'%name': entity.name} %}edit.caption{% endtrans %}</strong>
|
||||||
|
{% else %}
|
||||||
|
<strong>{% trans %}new.caption{% endtrans %}</strong>
|
||||||
|
{% endif %}
|
||||||
|
</legend>
|
||||||
|
|
||||||
|
<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>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content mb-3 mt-3">
|
||||||
|
<div id="home" class="tab-pane fade show active">
|
||||||
|
{{ form_row(form.name) }}
|
||||||
|
{{ form_row(form.parent) }}
|
||||||
|
{% block additional_controls %}{% endblock %}
|
||||||
|
{{ form_row(form.comment) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div id="info" class="tab-pane fade">
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-form-label col-md-3">{% trans %}id.label{% endtrans %}</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<p class="form-control-plaintext">{% if entity.iD %}{{ entity.id }}{% else %}-{% endif %}</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-form-label col-md-3">{% trans %}createdAt{% endtrans %}</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<p class="form-control-plaintext">
|
||||||
|
{% if entity.addedDate %}
|
||||||
|
{{ entity.addedDate | localizeddate("long") }}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group row">
|
||||||
|
<label class="col-form-label col-md-3">{% trans %}lastModified{% endtrans %}</label>
|
||||||
|
<div class="col-md-9">
|
||||||
|
<p class="form-control-plaintext">
|
||||||
|
{% if entity.lastModified %}
|
||||||
|
{{ entity.lastModified | localizeddate("long") }}
|
||||||
|
{% else %}
|
||||||
|
-
|
||||||
|
{% endif %}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_row(form.save) }}
|
||||||
|
{{ form_row(form.reset) }}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</fieldset>
|
||||||
|
|
||||||
|
{{ form_end(form) }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{% endblock %}
|
Loading…
Add table
Add a link
Reference in a new issue