api/src/Solidary/Admin/Service/StructureManager.php
<?php
/**
* Copyright (c) 2021, MOBICOOP. All rights reserved.
* This project is dual licensed under AGPL and proprietary licence.
***************************
* 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 <gnu.org/licenses>.
***************************
* Licence MOBICOOP described in the file
* LICENSE
*/
namespace App\Solidary\Admin\Service;
use App\Auth\Entity\AuthItem;
use App\Auth\Service\AuthManager as ServiceAuthManager;
use App\Auth\ServiceAdmin\AuthManager;
use App\Geography\Repository\TerritoryRepository;
use App\Solidary\Entity\Need;
use App\Solidary\Entity\Operate;
use App\Solidary\Entity\Structure;
use App\Solidary\Entity\StructureProof;
use App\Solidary\Entity\Subject;
use App\Solidary\Exception\SolidaryException;
use App\Solidary\Repository\StructureRepository;
use App\User\Entity\User;
use App\User\Repository\UserRepository;
use Doctrine\ORM\EntityManagerInterface;
/**
* Structure manager for admin context.
*
* @author Sylvain Briat <sylvain.briat@mobicoop.org>
*/
class StructureManager
{
private $entityManager;
private $territoryRepository;
private $userRepository;
private $authManager;
private $operateManager;
private $structureProofManager;
private $_authManagerBasic;
private $_structureRepository;
/**
* Constructor.
*/
public function __construct(
EntityManagerInterface $entityManager,
TerritoryRepository $territoryRepository,
UserRepository $userRepository,
AuthManager $authManager,
ServiceAuthManager $authManagerBasic,
OperateManager $operateManager,
StructureProofManager $structureProofManager,
StructureRepository $structureRepository
) {
$this->entityManager = $entityManager;
$this->territoryRepository = $territoryRepository;
$this->userRepository = $userRepository;
$this->authManager = $authManager;
$this->operateManager = $operateManager;
$this->structureProofManager = $structureProofManager;
$this->_authManagerBasic = $authManagerBasic;
$this->_structureRepository = $structureRepository;
}
/**
* Add a structure.
*
* @param Structure $structure The structure to add
* @param array $fields The fields
*
* @return Structure The structure created
*/
public function addStructure(Structure $structure, array $fields)
{
// treat territories
if (in_array('territories', array_keys($fields))) {
foreach ($fields['territories'] as $id) {
if ($territory = $this->territoryRepository->find($id)) {
$structure->addTerritory($territory);
} else {
throw new SolidaryException(SolidaryException::TERRITORY_INVALID);
}
}
}
// treat subjects
if (in_array('subjects', array_keys($fields))) {
foreach ($fields['subjects'] as $asubject) {
if (array_key_exists('label', $asubject) && null !== $asubject['label']) {
$subject = new Subject();
$subject->setLabel($asubject['label']);
$subject->setStructure($structure);
$structure->addSubject($subject);
$this->entityManager->persist($subject);
}
}
}
// treat needs
if (in_array('needs', array_keys($fields))) {
foreach ($fields['needs'] as $aneed) {
if (array_key_exists('label', $aneed) && null !== $aneed['label']) {
$need = new Need();
$need->setLabel($aneed['label']);
$need->setLabelVolunteer(isset($aneed['labelVolunteer']) ? $aneed['labelVolunteer'] : null);
$need->addStructure($structure);
$structure->addNeed($need);
$this->entityManager->persist($need);
}
}
}
// treat proofs
if (in_array('structureProofs', array_keys($fields))) {
foreach ($fields['structureProofs'] as $aproof) {
if (array_key_exists('label', $aproof) && null !== $aproof['label']) {
$proof = new StructureProof();
$proof->setLabel($aproof['label']);
$proof->setType($aproof['type']);
$proof->setMandatory(isset($aproof['mandatory']) && $aproof['mandatory'] ? true : false);
$proof->setPosition($aproof['position']);
$proof->setActivated($aproof['activated']);
$proof->setStructure($structure);
$proof->setCheckbox(false);
$proof->setRadio(false);
$proof->setInput(false);
$proof->setFile(false);
$proof->setSelectbox(false);
$proof->setOptions(null);
$proof->setAcceptedValues(null);
if (isset($aproof['checkbox']) && $aproof['checkbox']) {
$proof->setCheckbox(true);
} elseif (isset($aproof['radio']) && $aproof['radio']) {
$proof->setRadio(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
} elseif (isset($aproof['input']) && $aproof['input']) {
$proof->setInput(true);
} elseif (isset($aproof['file']) && $aproof['file']) {
$proof->setFile(true);
} elseif (isset($aproof['selectbox']) && $aproof['selectbox']) {
$proof->setSelectbox(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
}
$structure->addStructureProof($proof);
$this->entityManager->persist($proof);
}
}
}
// treat operators
if (in_array('operators', array_keys($fields))) {
foreach ($fields['operators'] as $operator) {
if ($user = $this->userRepository->find($operator['id'])) {
$operate = new Operate();
$operate->setUser($user);
$structure->addOperate($operate);
if ($authItem = $this->authManager->getAuthItem(AuthItem::ROLE_SOLIDARY_MANAGER)) {
$this->authManager->grant($user, $authItem, null, false);
}
} else {
throw new SolidaryException(SolidaryException::UNKNOWN_USER);
}
}
}
// reorder proofs (order may have changed during the persists)
$proofs = $structure->getStructureProofs();
$structure->removeStructureProofs();
usort($proofs, [$this, 'comparePosition']);
foreach ($proofs as $proof) {
$structure->addStructureProof($proof);
}
// persist the structure
$this->entityManager->persist($structure);
$this->entityManager->flush();
return $structure;
}
/**
* Patch a structure.
*
* @param Structure $structure The structure to update
* @param array $fields The updated fields
*
* @return Structure The structure updated
*/
public function patchStructure(Structure $structure, array $fields)
{
// check if territories have changed
if (in_array('territories', array_keys($fields))) {
// check if a territory has been removed
foreach ($structure->getTerritories() as $territory) {
if (!in_array($territory->getId(), $fields['territories'])) {
// territory removed
$structure->removeTerritory($territory);
}
}
// check if a territory has been added
$ids = [];
foreach ($structure->getTerritories() as $territory) {
$ids[] = $territory->getId();
}
foreach ($fields['territories'] as $id) {
if (!in_array($id, $ids)) {
// territory added, check if the territory exists
if ($territory = $this->territoryRepository->find($id)) {
$structure->addTerritory($territory);
} else {
throw new SolidaryException(SolidaryException::TERRITORY_INVALID);
}
}
}
}
// check if subjects have changed
if (in_array('subjects', array_keys($fields))) {
// check if a subject has been removed
$ids = [];
foreach ($fields['subjects'] as $value) {
if (array_key_exists('id', $value)) {
$ids[] = $value['id'];
}
}
foreach ($structure->getSubjects() as $subject) {
if (!in_array($subject->getId(), $ids)) {
// subject removed
$structure->removeSubject($subject);
}
}
foreach ($fields['subjects'] as $asubject) {
if (
array_key_exists('id', $asubject)
&& null !== $asubject['id']
&& array_key_exists('label', $asubject)
&& null !== $asubject['label']
) {
// existing subject => update
foreach ($structure->getSubjects() as $subject) {
if ($subject->getId() === $asubject['id']) {
$subject->setLabel($asubject['label']);
break;
}
}
} elseif (
!array_key_exists('id', $asubject)
&& array_key_exists('label', $asubject)
&& null !== $asubject['label']
) {
// new subject
$subject = new Subject();
$subject->setLabel($asubject['label']);
$subject->setStructure($structure);
$structure->addSubject($subject);
$this->entityManager->persist($subject);
}
}
}
// check if needs have changed
if (in_array('needs', array_keys($fields))) {
// check if a need has been removed
$ids = [];
foreach ($fields['needs'] as $value) {
if (array_key_exists('id', $value)) {
$ids[] = $value['id'];
}
}
foreach ($structure->getNeeds() as $need) {
if (!in_array($need->getId(), $ids)) {
// need removed
$structure->removeNeed($need);
}
}
foreach ($fields['needs'] as $aneed) {
if (
array_key_exists('id', $aneed)
&& null !== $aneed['id']
&& array_key_exists('label', $aneed)
&& null !== $aneed['label']
) {
// existing need => update
foreach ($structure->getNeeds() as $need) {
if ($need->getId() === $aneed['id']) {
$need->setLabel($aneed['label']);
$need->setLabelVolunteer(isset($aneed['labelVolunteer']) ? $aneed['labelVolunteer'] : null);
break;
}
}
} elseif (
!array_key_exists('id', $aneed)
&& array_key_exists('label', $aneed)
&& null !== $aneed['label']
) {
// new need
$need = new Need();
$need->setLabel($aneed['label']);
$need->setLabelVolunteer(isset($aneed['labelVolunteer']) ? $aneed['labelVolunteer'] : null);
$need->addStructure($structure);
$structure->addNeed($need);
$this->entityManager->persist($need);
}
}
}
// check if beneficiary proofs have changed
if (in_array('structureProofsRequester', array_keys($fields))) {
$ids = [];
foreach ($fields['structureProofsRequester'] as $proof) {
if (array_key_exists('id', $proof)) {
$ids[] = $proof['id'];
}
}
// check if a proof have been removed
foreach ($structure->getStructureProofs() as $proof) {
if (StructureProof::TYPE_REQUESTER == $proof->getType() && !in_array($proof->getId(), $ids)) {
// proof removed
$structure->removeStructureProof($proof);
$this->structureProofManager->deleteStructureProof($proof);
}
}
foreach ($fields['structureProofsRequester'] as $aproof) {
if (
array_key_exists('id', $aproof)
&& null !== $aproof['id']
&& array_key_exists('label', $aproof)
&& null !== $aproof['label']
) {
// existing proof => update
foreach ($structure->getStructureProofs() as $proof) {
/**
* @var StructureProof $proof
*/
if ($proof->getId() === $aproof['id']) {
$proof->setLabel($aproof['label']);
$proof->setType($aproof['type']);
$proof->setMandatory(isset($aproof['mandatory']) && $aproof['mandatory'] ? true : false);
$proof->setActivated($aproof['activated']);
$proof->setPosition($aproof['position']);
$proof->setCheckbox(false);
$proof->setRadio(false);
$proof->setInput(false);
$proof->setFile(false);
$proof->setSelectbox(false);
$proof->setOptions(null);
$proof->setAcceptedValues(null);
if (isset($aproof['checkbox']) && $aproof['checkbox']) {
$proof->setCheckbox(true);
} elseif (isset($aproof['radio']) && $aproof['radio']) {
$proof->setRadio(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
} elseif (isset($aproof['input']) && $aproof['input']) {
$proof->setInput(true);
} elseif (isset($aproof['file']) && $aproof['file']) {
$proof->setFile(true);
} elseif (isset($aproof['selectbox']) && $aproof['selectbox']) {
$proof->setSelectbox(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
}
break;
}
}
} elseif (
!array_key_exists('id', $aproof)
&& array_key_exists('label', $aproof)
&& null !== $aproof['label']
) {
// new proof
$proof = new StructureProof();
$proof->setLabel($aproof['label']);
$proof->setType($aproof['type']);
$proof->setMandatory(isset($aproof['mandatory']) && $aproof['mandatory'] ? true : false);
$proof->setActivated($aproof['activated']);
$proof->setPosition($aproof['position']);
$proof->setStructure($structure);
$proof->setCheckbox(false);
$proof->setRadio(false);
$proof->setInput(false);
$proof->setFile(false);
$proof->setSelectbox(false);
$proof->setOptions(null);
$proof->setAcceptedValues(null);
if (isset($aproof['checkbox']) && $aproof['checkbox']) {
$proof->setCheckbox(true);
} elseif (isset($aproof['radio']) && $aproof['radio']) {
$proof->setRadio(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
} elseif (isset($aproof['input']) && $aproof['input']) {
$proof->setInput(true);
} elseif (isset($aproof['file']) && $aproof['file']) {
$proof->setFile(true);
} elseif (isset($aproof['selectbox']) && $aproof['selectbox']) {
$proof->setSelectbox(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
}
$structure->addStructureProof($proof);
$this->entityManager->persist($proof);
}
}
}
// check if volunteer proofs have changed
if (in_array('structureProofsVolunteer', array_keys($fields))) {
$ids = [];
foreach ($fields['structureProofsVolunteer'] as $proof) {
if (array_key_exists('id', $proof)) {
$ids[] = $proof['id'];
}
}
// check if a proof have been removed
foreach ($structure->getStructureProofs() as $proof) {
if (StructureProof::TYPE_VOLUNTEER == $proof->getType() && !in_array($proof->getId(), $ids)) {
// proof removed
$structure->removeStructureProof($proof);
$this->structureProofManager->deleteStructureProof($proof);
}
}
foreach ($fields['structureProofsVolunteer'] as $aproof) {
if (
array_key_exists('id', $aproof)
&& null !== $aproof['id']
&& array_key_exists('label', $aproof)
&& null !== $aproof['label']
) {
// existing proof => update
foreach ($structure->getStructureProofs() as $proof) {
/**
* @var StructureProof $proof
*/
if ($proof->getId() === $aproof['id']) {
$proof->setLabel($aproof['label']);
$proof->setType($aproof['type']);
$proof->setMandatory(isset($aproof['mandatory']) && $aproof['mandatory'] ? true : false);
$proof->setActivated($aproof['activated']);
$proof->setPosition($aproof['position']);
$proof->setCheckbox(false);
$proof->setRadio(false);
$proof->setInput(false);
$proof->setFile(false);
$proof->setSelectbox(false);
$proof->setOptions(null);
$proof->setAcceptedValues(null);
if (isset($aproof['checkbox']) && $aproof['checkbox']) {
$proof->setCheckbox(true);
} elseif (isset($aproof['radio']) && $aproof['radio']) {
$proof->setRadio(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
} elseif (isset($aproof['input']) && $aproof['input']) {
$proof->setInput(true);
} elseif (isset($aproof['file']) && $aproof['file']) {
$proof->setFile(true);
} elseif (isset($aproof['selectbox']) && $aproof['selectbox']) {
$proof->setSelectbox(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
}
break;
}
}
} elseif (
!array_key_exists('id', $aproof)
&& array_key_exists('label', $aproof)
&& null !== $aproof['label']
) {
// new proof
$proof = new StructureProof();
$proof->setLabel($aproof['label']);
$proof->setType($aproof['type']);
$proof->setMandatory(isset($aproof['mandatory']) && $aproof['mandatory'] ? true : false);
$proof->setPosition($aproof['position']);
$proof->setActivated($aproof['activated']);
$proof->setStructure($structure);
$proof->setCheckbox(false);
$proof->setRadio(false);
$proof->setInput(false);
$proof->setFile(false);
$proof->setSelectbox(false);
$proof->setOptions(null);
$proof->setAcceptedValues(null);
if (isset($aproof['checkbox']) && $aproof['checkbox']) {
$proof->setCheckbox(true);
} elseif (isset($aproof['radio']) && $aproof['radio']) {
$proof->setRadio(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
} elseif (isset($aproof['input']) && $aproof['input']) {
$proof->setInput(true);
} elseif (isset($aproof['file']) && $aproof['file']) {
$proof->setFile(true);
} elseif (isset($aproof['selectbox']) && $aproof['selectbox']) {
$proof->setSelectbox(true);
$proof->setOptions(isset($aproof['options']) ? $aproof['options'] : null);
$proof->setAcceptedValues(isset($aproof['acceptedValues']) ? $aproof['acceptedValues'] : null);
}
$structure->addStructureProof($proof);
$this->entityManager->persist($proof);
}
}
}
// check if operators have changed
if (in_array('operators', array_keys($fields))) {
$ids = [];
foreach ($fields['operators'] as $operator) {
if (array_key_exists('id', $operator)) {
$ids[] = $operator['id'];
}
}
// check if an operator has been removed
foreach ($structure->getOperates() as $operate) {
if (!in_array($operate->getUser()->getId(), $ids)) {
// operator removed
// check if user is still an operator somewhere
$this->checkIsOperator($operate);
// remove operator for current structure
$structure->removeOperate($operate);
$this->operateManager->deleteOperate($operate);
}
}
// check if an operator has been added
$ids = [];
foreach ($structure->getOperates() as $operate) {
$ids[] = $operate->getUser()->getId();
}
foreach ($fields['operators'] as $operator) {
if (!in_array($operator['id'], $ids)) {
// operator added, check if the operator exists
if ($user = $this->userRepository->find($operator['id'])) {
$operate = new Operate();
$operate->setUser($user);
$structure->addOperate($operate);
if ($authItem = $this->authManager->getAuthItem(AuthItem::ROLE_SOLIDARY_MANAGER)) {
$this->authManager->grant($user, $authItem, null, false);
}
} else {
throw new SolidaryException(SolidaryException::UNKNOWN_USER);
}
}
}
}
// reorder proofs (order may have changed during the persists)
$proofs = $structure->getStructureProofs();
$structure->removeStructureProofs();
usort($proofs, [$this, 'comparePosition']);
foreach ($proofs as $proof) {
$structure->addStructureProof($proof);
}
// persist the structure
$this->entityManager->persist($structure);
$this->entityManager->flush();
// return the structure
return $structure;
}
/**
* Delete a structure.
*
* @param Structure $structure The structure to delete
*/
public function deleteStructure(Structure $structure)
{
$this->entityManager->remove($structure);
$this->entityManager->flush();
}
public function getStructuresForUser(User $user): array
{
if (empty($user->getOperates())) {
if ($this->_authManagerBasic->isAuthorized('structure_manage')) {
return $this->_structureRepository->findAllSorted();
}
return [];
}
$structures = [];
foreach ($user->getOperates() as $operate) {
array_push($structures, $operate->getStructure());
}
return $structures;
}
/**
* Check if the given operate user is operator elsewhere the given structure, and eventually remove the operate role.
*
* @param Operate $operate The operate that containes the user and structure
*
* @return bool
*/
private function checkIsOperator(Operate $operate)
{
$nbStructures = 0;
foreach ($operate->getUser()->getOperates() as $operated) {
/**
* @var Operate $operated
*/
if ($operated->getStructure()->getId() !== $operate->getStructure()->getId()) {
// the user is at least operator for another structure
++$nbStructures;
break;
}
}
if (0 == $nbStructures) {
// the user is not operator anymore
if ($authItem = $this->authManager->getAuthItem(AuthItem::ROLE_SOLIDARY_MANAGER)) {
$this->authManager->revoke($operate->getUser(), $authItem, null, false);
}
}
}
private function comparePosition($a, $b)
{
return strcmp($a->getPosition(), $b->getPosition());
}
}