mirror of
https://github.com/Part-DB/Part-DB-server.git
synced 2026-06-29 22:11:33 +00:00
parent
4d3e2e28a5
commit
e03eda84c5
7 changed files with 223 additions and 11 deletions
|
|
@ -30,7 +30,7 @@ use Doctrine\ORM\Mapping\Embeddable;
|
||||||
use Symfony\Component\Serializer\Annotation\Groups;
|
use Symfony\Component\Serializer\Annotation\Groups;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This class represents a reference to a info provider inside a part.
|
* This class represents a reference to an info provider inside a part.
|
||||||
* @see \App\Tests\Entity\Parts\InfoProviderReferenceTest
|
* @see \App\Tests\Entity\Parts\InfoProviderReferenceTest
|
||||||
*/
|
*/
|
||||||
#[Embeddable]
|
#[Embeddable]
|
||||||
|
|
@ -131,6 +131,7 @@ class InfoProviderReference
|
||||||
* @param string $provider_key
|
* @param string $provider_key
|
||||||
* @param string $provider_id
|
* @param string $provider_id
|
||||||
* @param string|null $provider_url
|
* @param string|null $provider_url
|
||||||
|
* @param \DateTimeImmutable|null $last_updated
|
||||||
* @return self
|
* @return self
|
||||||
*/
|
*/
|
||||||
public static function providerReference(string $provider_key, string $provider_id, ?string $provider_url = null): self
|
public static function providerReference(string $provider_key, string $provider_id, ?string $provider_url = null): self
|
||||||
|
|
@ -157,4 +158,15 @@ class InfoProviderReference
|
||||||
$ref->last_updated = new \DateTimeImmutable();
|
$ref->last_updated = new \DateTimeImmutable();
|
||||||
return $ref;
|
return $ref;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function create(?string $provider_key, ?string $provider_id, ?string $provider_url, ?\DateTimeImmutable $last_updated): self
|
||||||
|
{
|
||||||
|
$ref = new InfoProviderReference();
|
||||||
|
$ref->provider_key = $provider_key;
|
||||||
|
$ref->provider_id = $provider_id;
|
||||||
|
$ref->provider_url = $provider_url;
|
||||||
|
$ref->last_updated = $last_updated;
|
||||||
|
return $ref;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
106
src/Form/InfoProviderSystem/InfoProviderReferenceType.php
Normal file
106
src/Form/InfoProviderSystem/InfoProviderReferenceType.php
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
<?php
|
||||||
|
/*
|
||||||
|
* This file is part of Part-DB (https://github.com/Part-DB/Part-DB-symfony).
|
||||||
|
*
|
||||||
|
* Copyright (C) 2019 - 2026 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 Affero General Public License as published
|
||||||
|
* by the Free Software Foundation, either version 3 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 Affero General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU Affero General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
declare(strict_types=1);
|
||||||
|
|
||||||
|
|
||||||
|
namespace App\Form\InfoProviderSystem;
|
||||||
|
|
||||||
|
use App\Entity\Parts\InfoProviderReference;
|
||||||
|
use Symfony\Component\Form\AbstractType;
|
||||||
|
use Symfony\Component\Form\DataMapperInterface;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\TextType;
|
||||||
|
use Symfony\Component\Form\Extension\Core\Type\UrlType;
|
||||||
|
use Symfony\Component\Form\FormBuilderInterface;
|
||||||
|
use Symfony\Component\Form\FormInterface;
|
||||||
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
|
|
||||||
|
class InfoProviderReferenceType extends AbstractType implements DataMapperInterface
|
||||||
|
{
|
||||||
|
public function buildForm(FormBuilderInterface $builder, array $options): void
|
||||||
|
{
|
||||||
|
$builder
|
||||||
|
->setDataMapper($this)
|
||||||
|
->add('provider_key', ProviderSelectType::class, [
|
||||||
|
'label' => 'info_providers.provider_key',
|
||||||
|
'input' => 'string',
|
||||||
|
'multiple' => false,
|
||||||
|
'required' => false,
|
||||||
|
'only_active' => false,
|
||||||
|
])
|
||||||
|
->add('provider_id', TextType::class, [
|
||||||
|
'label' => 'info_providers.provider_id',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
->add('provider_url', UrlType::class, [
|
||||||
|
'label' => 'info_providers.provider_url',
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
|
;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
|
{
|
||||||
|
$resolver->setDefaults([
|
||||||
|
'data_class' => InfoProviderReference::class,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function mapDataToForms(mixed $viewData, \Traversable $forms): void
|
||||||
|
{
|
||||||
|
if ($viewData === null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$viewData instanceof InfoProviderReference) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @var FormInterface[] $forms */
|
||||||
|
$forms = iterator_to_array($forms);
|
||||||
|
|
||||||
|
$forms['provider_key']->setData($viewData->getProviderKey());
|
||||||
|
$forms['provider_id']->setData($viewData->getProviderId());
|
||||||
|
$forms['provider_url']->setData($viewData->getProviderUrl());
|
||||||
|
}
|
||||||
|
|
||||||
|
public function mapFormsToData(\Traversable $forms, mixed &$viewData): void
|
||||||
|
{
|
||||||
|
/** @var FormInterface[] $forms */
|
||||||
|
$forms = iterator_to_array($forms);
|
||||||
|
|
||||||
|
$providerKey = $forms['provider_key']->getData();
|
||||||
|
$providerId = $forms['provider_id']->getData();
|
||||||
|
$providerUrl = $forms['provider_url']->getData();
|
||||||
|
|
||||||
|
if ($viewData === null) {
|
||||||
|
$viewData = InfoProviderReference::noProvider();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$viewData instanceof InfoProviderReference) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$oldDate = $viewData->getLastUpdated();
|
||||||
|
$viewData = InfoProviderReference::create($providerKey, $providerId, $providerUrl, $oldDate);
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -31,12 +31,12 @@ use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
|
||||||
use Symfony\Component\OptionsResolver\Options;
|
use Symfony\Component\OptionsResolver\Options;
|
||||||
use Symfony\Component\OptionsResolver\OptionsResolver;
|
use Symfony\Component\OptionsResolver\OptionsResolver;
|
||||||
use Symfony\Component\Translation\StaticMessage;
|
use Symfony\Component\Translation\StaticMessage;
|
||||||
|
use Symfony\Component\Translation\TranslatableMessage;
|
||||||
|
|
||||||
class ProviderSelectType extends AbstractType
|
class ProviderSelectType extends AbstractType
|
||||||
{
|
{
|
||||||
public function __construct(private readonly ProviderRegistry $providerRegistry)
|
public function __construct(private readonly ProviderRegistry $providerRegistry)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public function getParent(): string
|
public function getParent(): string
|
||||||
|
|
@ -46,17 +46,22 @@ class ProviderSelectType extends AbstractType
|
||||||
|
|
||||||
public function configureOptions(OptionsResolver $resolver): void
|
public function configureOptions(OptionsResolver $resolver): void
|
||||||
{
|
{
|
||||||
$providers = $this->providerRegistry->getActiveProviders();
|
|
||||||
|
|
||||||
$resolver->setDefault('input', 'object');
|
$resolver->setDefault('input', 'object');
|
||||||
$resolver->setAllowedTypes('input', 'string');
|
$resolver->setAllowedTypes('input', 'string');
|
||||||
//Either the form returns the provider objects or their keys
|
//Either the form returns the provider objects or their keys
|
||||||
$resolver->setAllowedValues('input', ['object', 'string']);
|
$resolver->setAllowedValues('input', ['object', 'string']);
|
||||||
$resolver->setDefault('multiple', true);
|
$resolver->setDefault('multiple', true);
|
||||||
|
|
||||||
$resolver->setDefault('choices', function (Options $options) use ($providers) {
|
//Only show active providers in the list, or also inactive ones
|
||||||
|
$resolver->setDefault('only_active', true);
|
||||||
|
$resolver->setAllowedTypes('only_active', 'bool');
|
||||||
|
|
||||||
|
|
||||||
|
$resolver->setDefault('choices', function (Options $options) {
|
||||||
|
$providers = $options['only_active'] ? $this->providerRegistry->getActiveProviders() : $this->providerRegistry->getProviders();
|
||||||
|
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return $this->providerRegistry->getActiveProviders();
|
return $providers;
|
||||||
}
|
}
|
||||||
|
|
||||||
$tmp = [];
|
$tmp = [];
|
||||||
|
|
@ -69,20 +74,35 @@ class ProviderSelectType extends AbstractType
|
||||||
});
|
});
|
||||||
|
|
||||||
//The choice_label and choice_value only needs to be set if we want the objects
|
//The choice_label and choice_value only needs to be set if we want the objects
|
||||||
$resolver->setDefault('choice_label', function (Options $options){
|
$resolver->setDefault('choice_label', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::label($this, static fn (?InfoProviderInterface $choice) => new StaticMessage($choice?->getProviderInfo()['name']));
|
return ChoiceList::label($this, static fn(?InfoProviderInterface $choice
|
||||||
|
) => new StaticMessage($choice?->getProviderInfo()['name']));
|
||||||
}
|
}
|
||||||
|
|
||||||
return static fn ($choice, $key, $value) => new StaticMessage($key);
|
return static fn($choice, $key, $value) => new StaticMessage($key);
|
||||||
});
|
});
|
||||||
$resolver->setDefault('choice_value', function (Options $options) {
|
$resolver->setDefault('choice_value', function (Options $options) {
|
||||||
if ('object' === $options['input']) {
|
if ('object' === $options['input']) {
|
||||||
return ChoiceList::value($this, static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey());
|
return ChoiceList::value($this,
|
||||||
|
static fn(?InfoProviderInterface $choice) => $choice?->getProviderKey());
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
$resolver->setDefault('group_by', function (Options $options) {
|
||||||
|
//Do not show groups when only active providers are shown, because then all providers are active and the group would be useless
|
||||||
|
if ($options['only_active']) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return function ($choice, $key, string $value) {
|
||||||
|
if ($this->providerRegistry->getProviderByKey($value)->isActive()) {
|
||||||
|
return new TranslatableMessage('info_providers.providers_list.active');
|
||||||
|
}
|
||||||
|
return new TranslatableMessage('info_providers.providers_list.disabled');
|
||||||
|
};
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -33,6 +33,7 @@ use App\Entity\Parts\Part;
|
||||||
use App\Entity\Parts\PartCustomState;
|
use App\Entity\Parts\PartCustomState;
|
||||||
use App\Entity\PriceInformations\Orderdetail;
|
use App\Entity\PriceInformations\Orderdetail;
|
||||||
use App\Form\AttachmentFormType;
|
use App\Form\AttachmentFormType;
|
||||||
|
use App\Form\InfoProviderSystem\InfoProviderReferenceType;
|
||||||
use App\Form\ParameterType;
|
use App\Form\ParameterType;
|
||||||
use App\Form\Part\EDA\EDAPartInfoType;
|
use App\Form\Part\EDA\EDAPartInfoType;
|
||||||
use App\Form\Type\MasterPictureAttachmentType;
|
use App\Form\Type\MasterPictureAttachmentType;
|
||||||
|
|
@ -225,6 +226,10 @@ class PartBaseType extends AbstractType
|
||||||
'empty_data' => null,
|
'empty_data' => null,
|
||||||
'label' => 'part.gtin',
|
'label' => 'part.gtin',
|
||||||
])
|
])
|
||||||
|
->add('providerReference', InfoProviderReferenceType::class, [
|
||||||
|
'label' => false,
|
||||||
|
'required' => false,
|
||||||
|
])
|
||||||
;
|
;
|
||||||
|
|
||||||
//Comment section
|
//Comment section
|
||||||
|
|
|
||||||
|
|
@ -15,3 +15,24 @@
|
||||||
{{ form_row(form.partUnit) }}
|
{{ form_row(form.partUnit) }}
|
||||||
{{ form_row(form.partCustomState) }}
|
{{ form_row(form.partCustomState) }}
|
||||||
{{ form_row(form.gtin) }}
|
{{ form_row(form.gtin) }}
|
||||||
|
|
||||||
|
<div class="{{ offset_label }} {{ col_input }} ps-1">
|
||||||
|
<div class="accordion" id="accordionProviderReference">
|
||||||
|
<div class="accordion-item">
|
||||||
|
<h2 class="accordion-header">
|
||||||
|
<button class="accordion-button collapsed py-2" type="button" data-bs-toggle="collapse" data-bs-target="#collapseProviderReference" aria-expanded="true" aria-controls="collapseProviderReference">
|
||||||
|
<span>{% trans %}part.edit.provider_reference{% endtrans %}</span>
|
||||||
|
</button>
|
||||||
|
</h2>
|
||||||
|
<div id="collapseProviderReference" class="accordion-collapse collapse" data-bs-parent="#accordionProviderReference">
|
||||||
|
<div class="accordion-body">
|
||||||
|
<div class="alert alert-warning">
|
||||||
|
{% trans %}part.edit.provider_reference.warning{% endtrans %}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ form_widget(form.providerReference) }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -76,7 +76,7 @@
|
||||||
<a href="{{ part.providerReference.providerUrl }}" rel="noopener">
|
<a href="{{ part.providerReference.providerUrl }}" rel="noopener">
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<span title="{{ part.providerReference.providerKey }}">{{ info_provider_label(part.providerReference.providerKey)|default(part.providerReference.providerKey) }}</span>: {{ part.providerReference.providerId }}
|
<span title="{{ part.providerReference.providerKey }}">{{ info_provider_label(part.providerReference.providerKey)|default(part.providerReference.providerKey) }}</span>: {{ part.providerReference.providerId }}
|
||||||
<span> ({{ part.providerReference.lastUpdated | format_datetime() }})</span>
|
<span> ({{ part.providerReference.lastUpdated ? (part.providerReference.lastUpdated | format_datetime()) : ("part.info_provider_reference.updated_never"|trans) }})</span>
|
||||||
{% if part.providerReference.providerUrl %}
|
{% if part.providerReference.providerUrl %}
|
||||||
</a>
|
</a>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
|
||||||
|
|
@ -13697,5 +13697,53 @@ Buerklin-API Authentication server:
|
||||||
<target>You can use this randomly generated value (share it with nobody):</target>
|
<target>You can use this randomly generated value (share it with nobody):</target>
|
||||||
</segment>
|
</segment>
|
||||||
</unit>
|
</unit>
|
||||||
|
<unit id="cEwxoSj" name="info_providers.provider_key">
|
||||||
|
<segment>
|
||||||
|
<source>info_providers.provider_key</source>
|
||||||
|
<target>Info provider</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="0sjPRNV" name="info_providers.provider_id">
|
||||||
|
<segment>
|
||||||
|
<source>info_providers.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="2DzzAxZ" name="info_providers.provider_url">
|
||||||
|
<segment>
|
||||||
|
<source>info_providers.provider_url</source>
|
||||||
|
<target>Provider URL</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="4v3QmF6" name="part.edit.provider_reference">
|
||||||
|
<segment>
|
||||||
|
<source>part.edit.provider_reference</source>
|
||||||
|
<target>Info provider reference</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="9X2qEi7" name="log.element_edited.changed_fields.providerReference.provider_key">
|
||||||
|
<segment>
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_key</source>
|
||||||
|
<target>Information provider</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="MWXgWDb" name="log.element_edited.changed_fields.providerReference.provider_id">
|
||||||
|
<segment>
|
||||||
|
<source>log.element_edited.changed_fields.providerReference.provider_id</source>
|
||||||
|
<target>Provider ID</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="83fSFvo" name="part.info_provider_reference.updated_never">
|
||||||
|
<segment>
|
||||||
|
<source>part.info_provider_reference.updated_never</source>
|
||||||
|
<target>Never updated</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
|
<unit id="yIK_Wtj" name="part.edit.provider_reference.warning">
|
||||||
|
<segment>
|
||||||
|
<source>part.edit.provider_reference.warning</source>
|
||||||
|
<target>Warning: Changing values here can break the info retrieval mechanism! You should use the "update from info provider" functionality whenever possible.</target>
|
||||||
|
</segment>
|
||||||
|
</unit>
|
||||||
</file>
|
</file>
|
||||||
</xliff>
|
</xliff>
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue