diff --git a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php index 7a3c59668..5d7a4cc6e 100644 --- a/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php +++ b/src/Bundle/ChillThirdPartyBundle/Entity/ThirdParty.php @@ -85,6 +85,10 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface private ?string $nameCompany = ""; /** + * Canonicalized form composed of name, company name and acronym. + * + * This field is read-only, and is generated on database side. + * * @ORM\Column(name="canonicalized", type="text", options={"default":""}) */ private ?string $canonicalized = ""; @@ -116,7 +120,7 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface /** * Contact Persons: One Institutional ThirdParty has Many Contact Persons * @ORM\OneToMany(targetEntity="Chill\ThirdPartyBundle\Entity\ThirdParty", mappedBy="parent", - * cascade={"persist"}) + * cascade={"persist"}, orphanRemoval=true) * @var ThirdParty[]|Collection * @Assert\Valid(traverse=true) */ @@ -319,6 +323,17 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->email; } + public function isContactDataAnonymous(): bool + { + return $this->contactDataAnonymous; + } + + public function setContactDataAnonymous(bool $contactDataAnonymous): ThirdParty + { + $this->contactDataAnonymous = $contactDataAnonymous; + return $this; + } + /** * Set comment. * @@ -570,6 +585,47 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface return $this->children; } + /** + * Get the children where active = true + * + * @return Collection + */ + public function getActiveChildren(): Collection + { + return $this->children->filter(fn (ThirdParty $tp) => $tp->getActive()); + } + + /** + * Add a child and set the child as active + * + * Method used in conjonction with getActiveChildren in form. + * + * @internal use the method addChild + * @param ThirdParty $child + * @return $this + */ + public function addActiveChild(ThirdParty $child): self + { + $child->setActive(true); + + return $this->addChild($child); + } + + /** + * mark the child as unactive, but keep the child existing in the + * database. To effectively remove the child, use removeChild instead. + * + * @param ThirdParty $child + * @return $this + */ + public function removeActiveChild(ThirdParty $child): self + { + $child->setActive(false); + + return $this; + } + + /** * @param ThirdParty $child * @return $this @@ -583,13 +639,17 @@ class ThirdParty implements TrackCreationInterface, TrackUpdateInterface } /** + * Remove the child from the database. + * + * If you want to keep the child into the database + * but desactivate it, use removeActiveChildren instead. + * * @param ThirdParty $child * @return $this */ public function removeChild(ThirdParty $child): self { $this->children->removeElement($child); - $child->setActive(false); return $this; } diff --git a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php index a0527a07e..64c9fabda 100644 --- a/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php +++ b/src/Bundle/ChillThirdPartyBundle/Form/ThirdPartyType.php @@ -16,6 +16,7 @@ use Doctrine\ORM\QueryBuilder; use Doctrine\Persistence\ObjectManager; use Symfony\Component\Form\AbstractType; use Symfony\Component\Form\CallbackTransformer; +use Symfony\Component\Form\Extension\Core\Type\CheckboxType; use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; @@ -138,6 +139,10 @@ class ThirdPartyType extends AbstractType 'placeholder' => 'thirdparty.choose profession', 'required' => false ]) + ->add('contactDataAnonymous', CheckboxType::class, [ + 'required' => false, + 'label' => 'thirdparty.Contact data are confidential' + ]) ; // Institutional ThirdParty (parent) @@ -165,12 +170,13 @@ class ThirdPartyType extends AbstractType 'multiple' => true, 'attr' => ['class' => 'select2'] ]) - ->add('children', ChillCollectionType::class, [ + ->add('activeChildren', ChillCollectionType::class, [ 'entry_type' => ThirdPartyType::class, 'entry_options' => [ 'is_child' => true, 'block_name' => 'children' ], + 'block_name' => 'active_children', 'allow_add' => true, 'allow_delete' => true, 'by_reference' => false, diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig index b0968e7ad..38f1181e8 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form.html.twig @@ -23,7 +23,7 @@ {{ form_row(form.email) }}

{{ 'Contacts'|trans }}

- {{ form_widget(form.children) }} + {{ form_widget(form.activeChildren) }}
{{ form_label(form.address) }} diff --git a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form_thirdparty_children.html.twig b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form_thirdparty_children.html.twig index 44f4fc153..eac5c2a98 100644 --- a/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form_thirdparty_children.html.twig +++ b/src/Bundle/ChillThirdPartyBundle/Resources/views/ThirdParty/_form_thirdparty_children.html.twig @@ -1,5 +1,5 @@ -{% block _third_party_children_entry_widget %} +{% block _third_party_active_children_entry_widget %}
@@ -19,16 +19,27 @@
-
+
{{ form_widget(form.telephone) }} {{ form_errors(form.telephone) }} {{ form_label(form.telephone) }}
-
+
{{ form_widget(form.email) }} {{ form_errors(form.email) }} {{ form_label(form.email) }}
+
+ {{ form_widget(form.contactDataAnonymous) }} + {{ form_label(form.contactDataAnonymous) }} + {{ form_errors(form.contactDataAnonymous) }} +
+
+
+
+ {{ form_widget(form.comment) }} + {{ form_errors(form.comment) }} +
{% endblock %} diff --git a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php index 29a341b1b..47d5cc6b9 100644 --- a/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php +++ b/src/Bundle/ChillThirdPartyBundle/Search/ThirdPartyApiSearch.php @@ -20,9 +20,14 @@ class ThirdPartyApiSearch implements SearchApiInterface return (new SearchApiQuery) ->setSelectKey('tparty') ->setSelectJsonbMetadata("jsonb_build_object('id', tparty.id)") - ->setSelectPertinence("SIMILARITY(?, LOWER(UNACCENT(tparty.name)))", [ $pattern ]) + ->setSelectPertinence("GREATEST(". + "STRICT_WORD_SIMILARITY(LOWER(UNACCENT(?)), tparty.canonicalized),". + "(tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')::int". + ")", [ $pattern, $pattern ]) ->setFromClause('chill_3party.third_party AS tparty') - ->setWhereClause('SIMILARITY(LOWER(UNACCENT(?)), LOWER(UNACCENT(tparty.name))) > 0.20', [ $pattern ]) + ->setWhereClause("tparty.active IS TRUE ". + "AND (LOWER(UNACCENT(?)) <<% tparty.canonicalized OR ". + "tparty.canonicalized LIKE '%' || LOWER(UNACCENT(?)) || '%')", [ $pattern, $pattern ]) ; } @@ -33,7 +38,7 @@ class ThirdPartyApiSearch implements SearchApiInterface public function prepare(array $metadatas): void { - + } public function supportsResult(string $key, array $metadatas): bool diff --git a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php index a577b4ff0..a822f9efc 100644 --- a/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php +++ b/src/Bundle/ChillThirdPartyBundle/migrations/Version20211007165001.php @@ -22,19 +22,15 @@ final class Version20211007165001 extends AbstractMigration $this->addSql(" UPDATE chill_3party.third_party SET canonicalized = - COALESCE( - UNACCENT( - LOWER( - name || - CASE WHEN name <> '' THEN ' ' ELSE '' END || - name_company || - CASE WHEN name_company <> '' THEN ' ' ELSE '' END || - acronym || - CASE WHEN acronym <> '' THEN ' ' ELSE '' END - ) - ), - '' - ) + UNACCENT( + LOWER( + name || + CASE WHEN COALESCE(name_company, '') <> '' THEN ' ' ELSE '' END || + COALESCE(name_company, '') || + CASE WHEN COALESCE(acronym, '') <> '' THEN ' ' ELSE '' END || + COALESCE(acronym, '') + ) + ) "); $this->addSql(" CREATE OR REPLACE FUNCTION chill_3party.canonicalize() RETURNS TRIGGER @@ -42,14 +38,17 @@ final class Version20211007165001 extends AbstractMigration AS $$ BEGIN - NEW.canonicalized = UNACCENT(LOWER( - NEW.name || - CASE WHEN NEW.name <> '' THEN ' ' ELSE '' END || - NEW.name_company || - CASE WHEN NEW.name_company <> '' THEN ' ' ELSE '' END || - NEW.acronym || - CASE WHEN NEW.acronym <> '' THEN ' ' ELSE '' END - )); + NEW.canonicalized = + UNACCENT( + LOWER( + name || + CASE WHEN COALESCE(name_company, '') <> '' THEN ' ' ELSE '' END || + COALESCE(name_company, '') || + CASE WHEN COALESCE(acronym, '') <> '' THEN ' ' ELSE '' END || + COALESCE(acronym, '') + ) + ) + ; return NEW; END @@ -71,7 +70,7 @@ final class Version20211007165001 extends AbstractMigration "); $this->addSql(" CREATE INDEX chill_custom_canonicalized_trgm_idx_gist - ON chill_3party.third_party USING GIST (canonicalized gist_trgm_ops) + ON chill_3party.third_party USING GIST (canonicalized gist_trgm_ops) WHERE active IS TRUE "); }