<?php
declare(strict_types=1);
namespace App\Services\Contact;
use Doctrine\Persistence\ManagerRegistry;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Exception\UnprocessableEntityHttpException;
use Symfony\Component\Security\Core\Security;
use Symfony\Component\Form\Form;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
use App\Entity\{Contact, Csptype, Country, Campaign};
use App\Services\SerializerService;
use App\Repository\{ContactRepository, ContactConferenceRepository};
use App\Services\{
Contact\RelatedContactService,
Campaign\DatasetService,
};
use App\Event\CampaignUpdateHistoryEvent;
use App\Common\Traits\FormatTextToExportTrait;
class ContactService
{
use FormatTextToExportTrait;
private const CSV_EXPORT_FILENAME = 'contacts-export';
private ManagerRegistry $doctrine;
private RequestStack $requestStack;
private Security $security;
private EventDispatcherInterface $dispatcher;
private SerializerService $serializerService;
private ContactRepository $contactRepository;
private DatasetService $datasetService;
private RelatedContactService $relatedContactService;
private ContactConferenceRepository $contactConferenceRepository;
public function __construct(
ManagerRegistry $doctrine,
RequestStack $requestStack,
Security $security,
EventDispatcherInterface $dispatcher,
SerializerService $serializerService,
ContactRepository $contactRepository,
DatasetService $datasetService,
RelatedContactService $relatedContactService,
ContactConferenceRepository $contactConferenceRepository
) {
$this->doctrine = $doctrine;
$this->requestStack = $requestStack;
$this->security = $security;
$this->dispatcher = $dispatcher;
$this->serializerService = $serializerService;
$this->contactRepository = $contactRepository;
$this->datasetService = $datasetService;
$this->relatedContactService = $relatedContactService;
$this->contactConferenceRepository = $contactConferenceRepository;
}
public function getList(
int $mode,
?array $sort = [],
int $from = null,
int $to = null
): mixed {
$session = $this->requestStack->getSession();
$contactSearchCriteria = $session->has('contactSearchCriteria')
? $session->get('contactSearchCriteria')
: []
;
$contacts = $this->contactRepository->findList($mode, $sort, $from, $to, $contactSearchCriteria);
if (in_array($mode, [1, 3])) {
return $contacts;
}
return json_encode($contacts);
}
public function getContactsCount(): int
{
return $this->contactRepository->findList(1)['itemsCount'];
}
public function getContactCspsAndCountriesCount()
{
$session = $this->requestStack->getSession();
$contactSearchCriteria = $session->has('contactSearchCriteria')
? $session->get('contactSearchCriteria')
: []
;
$counts = $this->contactRepository->findList(1, [], null, null, $contactSearchCriteria, true);
return [
'cspsCount' => $counts['cspsCount'],
'countriesCount' => $counts['countriesCount'],
'cspCountryCount' => $counts['cspCountryCount'],
];
}
public function getCspContactCount(): int
{
return $this->contactRepository->getTotalCspContactCount();
}
public function getCountryContactCount(): int
{
return $this->contactRepository->getTotatCountryContactCount();
}
public function getCspCountryContactCount(): int
{
return $this->contactRepository->getTotatCspCountryContactCount();
}
/**
* @throws Exception
* @throws UnprocessableEntityHttpException
*/
public function saveContact(
Contact $contact,
Form $form,
bool $editMod,
int $csptypeId,
?int $countryId,
?string $operation = null,
?Contact $refContact = null,
?Campaign $campaign = null,
?Contact $sourceContact = null
): void {
if (false === $editMod && $operation !== Contact::OPERATION_UPDATE) {
$this->checkIfEmailExists($contact);
}
$entityManager = $this->doctrine->getManager();
$entityManager->getConnection()->beginTransaction();
try {
$contact->setCsptype($entityManager->getReference(Csptype::class, $csptypeId));
if ($countryId) {
$contact->setCountry($entityManager->getReference(Country::class, $countryId));
}
$entityManager->persist($contact);
$entityManager->flush();
$updateHistory = false;
if (null !== $campaign) {
if (false === $editMod) {
$this->datasetService->addContactToDataset($campaign, $contact, $operation, $refContact);
$updateHistory = true;
} else {
$this->datasetService->saveCampaignContactData($campaign, $contact, $form);
if ($sourceContact && false === $contact->equals($sourceContact)) {
$updateHistory = true;
}
}
}
if (
$operation === Contact::OPERATION_RELATED
&& $refContact instanceof Contact
) {
$this->relatedContactService->linkRelatedContacts($refContact, $contact);
}
if (
$operation === Contact::OPERATION_UPDATE
&& $refContact instanceof Contact
) {
$this->contactConferenceRepository->updateContactConferences($contact, $refContact);
$entityManager->remove($refContact);
$entityManager->flush();
}
if (true === $updateHistory) {
if ($operation === Contact::OPERATION_UPDATE) {
$entityManager->clear();
}
$this->dispatchCampaignUpdateHistory($campaign);
}
$entityManager->getConnection()->commit();
} catch (\Exception $exception) {
$entityManager->getConnection()->rollBack();
throw $exception;
}
}
private function dispatchCampaignUpdateHistory(Campaign $campaign): void
{
$this->dispatcher->dispatch(
new CampaignUpdateHistoryEvent($campaign, $this->security->getUser()),
CampaignUpdateHistoryEvent::NAME
);
}
/**
* @throws UnprocessableEntityHttpException
*/
private function checkIfEmailExists(Contact $contact): void
{
$checkContactEmail = $this->doctrine->getRepository(Contact::class)->findOneBy(
['email' => $contact->getEmail(),]
);
if ($checkContactEmail instanceof Contact) {
throw new UnprocessableEntityHttpException('The contact you are trying to add already exists in the CRM.<br />Please search and add using their email address');
}
}
public function setContactLockStatus(Contact $contact, bool $lockStatus, bool $forceUnlock = false): void
{
if (
(true === $lockStatus && null !== $contact->getLockDate() && null !== $contact->getLockUser())
|| (false === $forceUnlock && false === $lockStatus && $this->security->getUser() !== $contact->getLockUser())
) {
return;
}
$entityManager = $this->doctrine->getManager();
$contact
->setLockDate(true === $lockStatus ? new \DateTime() : null)
->setLockUser(true === $lockStatus ? $this->security->getUser() : null)
;
$entityManager->flush();
}
public function moveToTrash(Contact $contact): void
{
$entityManager = $this->doctrine->getManager();
$contact
->setTrash(true)
->setLockDate(null)
->setLockUser(null)
;
$entityManager->flush();
}
public function getCsvExportFilename(): string
{
return sprintf('%s-%s.csv', self::CSV_EXPORT_FILENAME, (new \DateTime())->format('YmdHis'));
}
public function getCsvExportData(array $data): string
{
ini_set('memory_limit', -1);
$rows = new \SplFixedArray(count($data) + 1);
$line = ["ID", "Company", "Group", "Country", "Region", "Industry", "Company Type", "Title", "Firstname",
"Lastname", "Position", "Division", "Direct Phone Number", "Mobile Phone Number",
"Email Address", "National headquarter switchboard phone number",];
if ($this->security->isGranted('ROLE_PM')) {
$line = array_merge(
$line,
["LinkedIn Profile", "Valid email", "Comments", "Last update", "Conferences", "Source",]
);
}
//$rows = implode(';', $line) . "\n";
$i = 0;
$rows[$i++] = implode(';', $line); // . "\n";
foreach ($data as $contact) {
/*$rows .= $contact['id'].";".
$contact['cspName'].";".
$contact['cspGroup'].";".
$contact['countryName'].";".
$contact['regionName'].";".
$contact['csptypeName'].";".
$contact['title'].";".
$contact['fname'].";".
$contact['lname'].";".
$contact['position'].";".
$contact['division'].";".
$contact['phone1'].";".
$contact['phone2'].";".
$contact['email'].";".
$contact['switchboardPhone']
;
if ($this->security->isGranted('ROLE_PM')) {
$rows .= ";".$contact['linkedinUrl'].";".
(int) $contact['validEmail'].";".
$contact['comment'].";".
((null !== $contact['updatedAt']) ? $contact['updatedAt']->format('d/m/Y H:i') : '').";".
$contact['conferences'].";".
$contact['sourceName']
;
}*/
$line = sprintf(
"%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s;%s",
$contact['id'],
$contact['cspName'],
$contact['cspGroup'],
$contact['countryName'],
$contact['regionName'],
$contact['csptypeName'],
$contact['companyTypes'],
$contact['title'],
$contact['fname'],
$contact['lname'],
$contact['position'],
$contact['division'],
$contact['phone1'],
$contact['phone2'],
$contact['email'],
$contact['switchboardPhone']
);
if ($this->security->isGranted('ROLE_PM')) {
$comment = $this->formatTextToExport($contact['comment']);
$line .= sprintf(
";%s;%s;%s;%s;%s;%s",
$contact['linkedinUrl'],
(int) $contact['validEmail'],
$comment,
(null !== $contact['updatedAt']) ? $contact['updatedAt']->format('d/m/Y H:i') : '',
$contact['conferences'],
$contact['sourceName']
);
}
//$line .= "\n";
$rows[$i++] = $line;
}
//return $rows;
return implode("\n", $rows->toArray());
}
public function findContactDuplicates(Contact $contact, string $dup): array
{
$filter = $dup === 'name'
? ['fname' => $contact->getFname(), 'lname' => $contact->getLname(), 'csp' => $contact->getCsp(), 'trash' => false,]
: ['email' => $contact->getEmail(), 'trash' => false,]
;
$duplicates = $this->contactRepository->findBy($filter);
foreach ($duplicates as $key => $dup) {
if ($dup->getId() === $contact->getId()) {
unset($duplicates[$key]);
}
}
return array_values($duplicates);
}
}