Added very basic controls to edit a projects BOM

This commit is contained in:
Jan Böhmer 2022-12-23 13:12:22 +01:00
parent b1ed52bcc3
commit c78bc01d23
6 changed files with 158 additions and 7 deletions

View file

@ -52,7 +52,7 @@ class Project extends AbstractStructuralDBElement
protected $parent; protected $parent;
/** /**
* @ORM\OneToMany(targetEntity="ProjectBOMEntry", mappedBy="project") * @ORM\OneToMany(targetEntity="ProjectBOMEntry", mappedBy="project", cascade={"persist", "remove"}, orphanRemoval=true)
*/ */
protected $bom_entries; protected $bom_entries;
@ -96,6 +96,23 @@ class Project extends AbstractStructuralDBElement
$this->bom_entries = new ArrayCollection(); $this->bom_entries = new ArrayCollection();
} }
public function __clone()
{
//When cloning this project, we have to clone each bom entry too.
if ($this->id) {
$bom_entries = $this->bom_entries;
$this->bom_entries = new ArrayCollection();
//Set master attachment is needed
foreach ($bom_entries as $bom_entry) {
$clone = clone $bom_entry;
$this->bom_entries->add($clone);
}
}
//Parent has to be last call, as it resets the ID
parent::__clone();
}
/** /**
* Get the order quantity of this device. * Get the order quantity of this device.
* *
@ -154,20 +171,31 @@ class Project extends AbstractStructuralDBElement
} }
/** /**
* @return mixed * @return Collection<int, ProjectBOMEntry>|ProjectBOMEntry[]
*/ */
public function getBomEntries() public function getBomEntries(): Collection
{ {
return $this->bom_entries; return $this->bom_entries;
} }
/** /**
* @param mixed $bom_entries * @param ProjectBOMEntry $entry
* @return Project * @return $this
*/ */
public function setBomEntries($bom_entries) public function addBomEntry(ProjectBOMEntry $entry): self
{ {
$this->bom_entries = $bom_entries; $entry->setProject($this);
$this->bom_entries->add($entry);
return $this;
}
/**
* @param ProjectBOMEntry $entry
* @return $this
*/
public function removeBomEntry(ProjectBOMEntry $entry): self
{
$this->bom_entries->removeElement($entry);
return $this; return $this;
} }

View file

@ -32,6 +32,7 @@ use Symfony\Component\Validator\Constraints as Assert;
* The ProjectBOMEntry class represents a entry in a project's BOM. * The ProjectBOMEntry class represents a entry in a project's BOM.
* *
* @ORM\Table("device_parts") * @ORM\Table("device_parts")
* @ORM\HasLifecycleCallbacks()
* @ORM\Entity() * @ORM\Entity()
*/ */
class ProjectBOMEntry extends AbstractDBElement class ProjectBOMEntry extends AbstractDBElement

View file

@ -21,7 +21,9 @@
namespace App\Form\AdminPages; namespace App\Form\AdminPages;
use App\Entity\Base\AbstractNamedDBElement; use App\Entity\Base\AbstractNamedDBElement;
use App\Form\ProjectSystem\ProjectBOMEntryType;
use App\Form\Type\RichTextEditorType; use App\Form\Type\RichTextEditorType;
use Symfony\Component\Form\Extension\Core\Type\CollectionType;
use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormBuilderInterface;
class ProjectAdminForm extends BaseEntityAdminForm class ProjectAdminForm extends BaseEntityAdminForm
@ -38,5 +40,17 @@ class ProjectAdminForm extends BaseEntityAdminForm
'rows' => 2, 'rows' => 2,
], ],
]); ]);
$builder->add('bom_entries', CollectionType::class, [
'entry_type' => ProjectBOMEntryType::class,
'entry_options' => [
'label' => false,
],
'allow_add' => true,
'allow_delete' => true,
'by_reference' => false,
'reindex_enable' => true,
'label' => false,
]);
} }
} }

View file

@ -0,0 +1,67 @@
<?php
namespace App\Form\ProjectSystem;
use App\Entity\Parts\Part;
use App\Entity\ProjectSystem\ProjectBOMEntry;
use Svg\Tag\Text;
use Symfony\Bridge\Doctrine\Form\Type\EntityType;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\NumberType;
use Symfony\Component\Form\Extension\Core\Type\TextType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolver;
class ProjectBOMEntryType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder
->add('quantity', NumberType::class, [
'label' => 'project.bom.quantity',
])
->add('part', EntityType::class, [
'class' => Part::class,
'choice_label' => 'name',
'required' => false,
])
->add('name', TextType::class, [
'label' => 'project.bom.name',
'required' => false,
'empty_data' => ''
])
->add('mountnames', TextType::class, [
'required' => false,
'label' => 'project.bom.mountnames',
'empty_data' => '',
'attr' => [
'class' => 'tagsinput',
'data-controller' => 'elements--tagsinput',
]
])
->add('comment', TextType::class, [
'required' => false,
'label' => 'project.bom.comment',
'empty_data' => ''
])
;
}
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'data_class' => ProjectBOMEntry::class,
]);
}
public function getBlockPrefix()
{
return 'project_bom_entry';
}
}

View file

@ -12,6 +12,32 @@
{% trans %}device.new{% endtrans %} {% trans %}device.new{% endtrans %}
{% endblock %} {% endblock %}
{% block additional_pills %}
<li class="nav-item"><a data-bs-toggle="tab" class="nav-link link-anchor" href="#bom">BOM</a></li>
{% endblock %}
{% block additional_controls %} {% block additional_controls %}
{{ form_row(form.description) }} {{ form_row(form.description) }}
{% endblock %}
{% block additional_panes %}
<div class="tab-pane" id="bom">
{% form_theme form.bom_entries with ['Form/collection_types_layout.html.twig'] %}
{% import 'components/collection_type.macro.html.twig' as collection %}
<div {{ collection.controller(form.bom_entries, 'attachment.edit.delete.confirm') }}>
<table class="table table-striped table-sm" {{ collection.target() }}>
<tbody>
{% for attachment in form.bom_entries %}
{{ form_widget(attachment) }}
{% endfor %}
</tbody>
</table>
<button type="button" class="btn btn-success" {{ collection.create_btn() }}>
<i class="fas fa-plus-square fa-fw"></i>
{% trans %}attachment.create{% endtrans %}
</button>
</div>
</div>
{% endblock %} {% endblock %}

View file

@ -0,0 +1,15 @@
{% block project_bom_entry_widget %}
{% import 'components/collection_type.macro.html.twig' as collection %}
<tr>
<td>
{{ form_widget(form) }}
</td>
<td>
<button type="button" class="btn btn-danger lot_btn_delete" {{ collection.delete_btn() }}>
<i class="fas fa-trash-alt fa-fw"></i>
{% trans %}part_lot.delete{% endtrans %}
</button>
{{ form_errors(form) }}
</td>
</tr>
{% endblock %}