client/src/MobicoopBundle/Carpool/Service/AdManager.php
<?php
/**
* Copyright (c) 2019, 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 Mobicoop\Bundle\MobicoopBundle\Carpool\Service;
use Mobicoop\Bundle\MobicoopBundle\Api\Service\DataProvider;
use Mobicoop\Bundle\MobicoopBundle\Carpool\Entity\Ad;
use Symfony\Component\Security\Core\Security;
/**
* Ad management service.
*/
class AdManager
{
private $dataProvider;
private $security;
/**
* Constructor.
*
* @throws \ReflectionException
*/
public function __construct(DataProvider $dataProvider, Security $security)
{
$this->dataProvider = $dataProvider;
$this->dataProvider->setClass(Ad::class, Ad::RESOURCE_NAME);
$this->dataProvider->setFormat(DataProvider::RETURN_OBJECT);
$this->security = $security;
}
/**
* Get an ad and its results.
*
* @param int $id The ad id
* @param null|array The filters to apply to the results
*
* @return null|Ad
*/
public function getAd(int $id, ?array $filters = null)
{
if ($data = $this->dataProvider->getItem($id, $filters)) {
return $data->getValue();
}
return null;
}
/**
* Get an ad and its results from its external id.
*
* @param string $id The ad external id
* @param null|array The filters to apply to the results
*
* @return null|Ad
*/
public function getAdFromExternalId(string $id, ?array $filters = null)
{
if ($data = $this->dataProvider->getSpecialItem($id, 'external', $filters)) {
return $data->getValue();
}
return null;
}
/**
* Get full ad data.
*
* @return null|Ad
*/
public function getFullAd(int $id)
{
if ($data = $this->dataProvider->getSpecialItem($id, 'full')) {
return $data->getValue();
}
return null;
}
/**
* Claim an Ad (useful for login or register after an anonymous search).
*
* @param int $id The Ad id to claim
*
* @return bool Result of the claim
*/
public function claimAd(int $id)
{
$ad = new Ad($id);
if ($response = $this->dataProvider->putSpecial($ad, null, 'claim')) {
return 200 == $response->getCode();
}
return false;
}
/**
* Create an ad. The ad can be a search.
*
* @param array $data The data used to create the ad
*
* @return Ad
*/
public function createAd(array $data)
{
$ad = $this->mapAd($data);
// creation of the ad
$response = $this->dataProvider->post($ad);
if (201 != $response->getCode()) {
return $response->getValue();
}
return $response->getValue();
}
/**
* Get all results for a search.
*
* @param array $origin The origin address
* @param array $destination The destination address
* @param \Datetime $date The date in a Datetime object
* @param \Datetime $time The time in a Datetime object
* @param bool $regular The trip is regular
* @param null|bool $strictDate Strict date
* @param bool $strictPunctual Strictly punctual
* @param bool $strictRegular Strictly regular
* @param null|int $role Role (driver and/or passenger)
* @param null|int $userId User id of the requester (to exclude its own results)
* @param int $communityId Community id of the requester (to get only results from that community)
* @param null|array $filters Filters and order choices
*
* @return null|Ad the matchings found or null if not found
*/
public function getResultsForSearch(
array $origin,
array $destination,
?\DateTime $date,
?\DateTime $time,
bool $regular,
?bool $strictDate = null,
?bool $strictPunctual = null,
?bool $strictRegular = null,
?int $role = null,
?int $userId = null,
?int $communityId = null,
?array $filters = null
) {
// we set the params
$params = [
'origin' => $origin,
'destination' => $destination,
'waypoints' => [],
'outwardDate' => $date,
'regular' => $regular,
'search' => true,
'communities' => [],
];
if (!is_null($strictDate)) {
$params['strictDate'] = $strictDate;
}
if (!is_null($time)) {
$params['outwardTime'] = $time;
}
if (!is_null($strictPunctual)) {
$params['strictPunctual'] = $strictPunctual;
}
if (!is_null($strictRegular)) {
$params['strictRegular'] = $strictRegular;
}
if (!is_null($role)) {
$params['driver'] = 1 == $role || 3 == $role;
$params['passenger'] = 2 == $role || 3 == $role;
}
if (!is_null($userId)) {
$params['userId'] = $userId;
}
if (!is_null($communityId)) {
$params['communities'] = [$communityId];
}
if (!is_null($filters)) {
$params['filters'] = $filters;
}
return $this->createAd($params);
}
/**
* Create an ask from an ad result.
*
* @param array $data The data used to create the ask
* @param null|bool $formal If the ask is formal
*
* @return ad
*/
public function createAsk(array $params, ?bool $formal = false)
{
if (!isset($params['regular']) || !isset($params['adId']) || !isset($params['matchingId'])) {
return null;
}
$ad = new Ad();
// role
$ad->setRole($params['driver'] ? ($params['passenger'] ? Ad::ROLE_DRIVER_OR_PASSENGER : Ad::ROLE_DRIVER) : Ad::ROLE_PASSENGER);
// ad
$ad->setAdId($params['adId']);
// matching
$ad->setMatchingId($params['matchingId']);
if ($params['regular'] && $formal) {
// formal regular ask, we have to transform the outward and return schedule to a unique schedule array
if (!isset($params['outwardSchedule']) && !isset($params['returnSchedule'])) {
return null;
}
$schedule = [];
$days = ['mon', 'tue', 'wed', 'thu', 'fri', 'sat', 'sun'];
foreach ($days as $day) {
if (isset($params['outwardSchedule'][$day.'Time']) && !is_null($params['outwardSchedule'][$day.'Time'])) {
if (isset($params['returnSchedule'][$day.'Time']) && !is_null($params['returnSchedule'][$day.'Time'])) {
$schedule[] = [
'outwardTime' => $params['outwardSchedule'][$day.'Time'],
'returnTime' => $params['returnSchedule'][$day.'Time'],
$day => true,
];
} else {
$schedule[] = [
'outwardTime' => $params['outwardSchedule'][$day.'Time'],
'returnTime' => '',
$day => true,
];
}
} elseif (isset($params['returnSchedule'][$day.'Time']) && !is_null($params['returnSchedule'][$day.'Time'])) {
$schedule[] = [
'outwardTime' => '',
'returnTime' => $params['returnSchedule'][$day.'Time'],
$day => true,
];
}
}
$ad->setSchedule($schedule);
$ad->setOutwardDate(\DateTime::createFromFormat('Y-m-d', $params['fromDate']));
$ad->setOutwardLimitdate(\DateTime::createFromFormat('Y-m-d', $params['toDate']));
} elseif (!$params['regular'] && $params['time']) {
$ad->setOutwardTime($params['time']);
}
// creation of the ad ask
if ($formal) {
$response = $this->dataProvider->post($ad, 'ask');
} else {
$response = $this->dataProvider->post($ad, 'contact');
}
return $response->getValue();
}
/**
* Get an ad and its results by its related Ask.
*
* @param int $askId Id of the related Ask
* @param int $userId The user that make the request
*
* @return null|Ad
*/
public function getAdAsk(int $askId, int $userId)
{
if ($data = $this->dataProvider->getSpecialItem($askId, 'ask', ['userId' => $userId], true)) {
return $data->getValue();
}
return null;
}
/**
* Update an Ask via the Ad.
*
* @param int $ad The ad to update
* @param int $userId The user that make the request
*
* @return null|Ad
*/
public function updateAdAsk(Ad $ad, int $userId)
{
if ($data = $this->dataProvider->putSpecial($ad, null, 'ask', ['userId' => $userId], true)) {
return $data->getValue();
}
return null;
}
/**
* Update an Ad.
*
* @param null|Ad $ad - the current ad before update
*
* @return array|object
*
* @throws \Exception
*/
public function updateAd(array $data, Ad $ad = null)
{
$ad = $this->mapAd($data, $ad);
if ($data = $this->dataProvider->put($ad, null, ['mail_search_link' => $data['mailSearchLink']])) {
return $data->getValue();
}
return null;
}
/**
* Delete an Ad.
*
* @param int $id The id of the ad to delete
* @param array $data
*
* @return bool the result of the deletion
*/
public function deleteAd(int $id, ?array $data)
{
if ($this->dataProvider->delete($id, $data)) {
return 'success';
}
return null;
}
/**
* Map data json array to and Ad.
*
* @param Ad $ad - the current Ad before update
*
* @throws \Exception
*/
public function mapAd(array $data, Ad $ad = null): Ad
{
if (is_null($ad)) {
$ad = new Ad();
}
/**
* @var User $poster
*/
$poster = $this->security->getUser();
if (!is_null($poster) && isset($data['userDelegated']) && $data['userDelegated'] != $poster->getId()) {
$data['userId'] = $data['userDelegated'];
$data['posterId'] = $poster->getId();
} elseif (!is_null($poster)) {
$data['userId'] = $poster->getId();
}
if (!isset($data['outwardDate']) || '' == $data['outwardDate']) {
// $data['outwardDate'] = new \DateTime();
} elseif (is_string($data['outwardDate'])) {
$data['outwardDate'] = \DateTime::createFromFormat('Y-m-d', $data['outwardDate']);
}
if (isset($data['returnDate']) && is_string($data['returnDate']) && '' != $data['returnDate']) {
$data['returnDate'] = \DateTime::createFromFormat('Y-m-d', $data['returnDate']);
$ad->setOneWay(false); // only for punctual journey
} else {
if (!isset($data['regular']) || !$data['regular']) {
$ad->setOneWay(true); // only for punctual journey
}
}
// one-way for regular
if (isset($data['regular']) && $data['regular'] && isset($data['schedules'])) {
$ad->setOneWay(true);
foreach ($data['schedules'] as $schedule) {
if (isset($schedule['returnTime'])) {
$ad->setOneWay(false);
}
}
}
if (isset($data['id'])) {
$ad->setId($data['id']);
$ad->setAdId($data['id']);
$ad->setProposalId($data['id']);
}
if (isset($data['paused'])) {
$ad->setPaused($data['paused']);
}
// the ad is a search ?
if (isset($data['search'])) {
$ad->setSearch($data['search']);
}
// role
if (isset($data['driver']) || isset($data['passenger'])) {
$ad->setRole(isset($data['driver']) && $data['driver']
? (isset($data['passenger']) && $data['passenger']
? Ad::ROLE_DRIVER_OR_PASSENGER
: Ad::ROLE_DRIVER)
: Ad::ROLE_PASSENGER);
}
// frequency
if (isset($data['regular'])) {
$ad->setFrequency($data['regular'] ? Ad::FREQUENCY_REGULAR : Ad::FREQUENCY_PUNCTUAL);
}
// outward waypoints
if (isset($data['origin'], $data['waypoints'])) {
$outwardWaypoints[] = $data['origin'];
$returnWaypoints = null;
foreach ($data['waypoints'] as $waypoint) {
if ($waypoint['visible']) {
$outwardWaypoints[] = $waypoint['address'];
}
}
$outwardWaypoints[] = $data['destination'];
if (!$ad->isOneWay()) {
$returnWaypoints = array_reverse($outwardWaypoints, false);
}
$ad->setOutwardWaypoints($outwardWaypoints);
$ad->setReturnWaypoints($returnWaypoints);
}
// date and time
if (Ad::FREQUENCY_REGULAR == $ad->getFrequency()) {
if (isset($data['fromDate'])) {
$ad->setOutwardDate(\DateTime::createFromFormat('Y-m-d', $data['fromDate']));
} else {
$ad->setOutwardDate(new \DateTime());
}
if (isset($data['toDate'])) {
$ad->setOutwardLimitdate(\DateTime::createFromFormat('Y-m-d', $data['toDate']));
}
if (isset($data['schedules'])) {
$ad->setSchedule($data['schedules']);
}
} elseif (isset($data['outwardDate'])) {
$ad->setOutwardDate($data['outwardDate']);
if (isset($data['outwardTime'])) {
if ($data['outwardTime'] instanceof \DateTime) {
$ad->setOutwardTime($data['outwardTime']->format('H:i'));
} elseif (is_string($data['outwardTime']) && preg_match('/^([01]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/', $data['outwardTime'])) {
$ad->setOutwardTime($data['outwardTime']);
} else {
throw new \LogicException('The timetable transmitted is not in the expected format');
}
}
if (isset($data['returnDate'], $data['returnTime'])) {
$ad->setOneWay(false);
$ad->setReturnDate($data['returnDate']);
$ad->setReturnTime($data['returnTime']);
}
}
if (isset($data['strictDate'])) {
$ad->setStrictDate($data['strictDate']);
}
if (isset($data['strictPunctual'])) {
$ad->setStrictPunctual($data['strictPunctual']);
}
if (isset($data['strictRegular'])) {
$ad->setStrictRegular($data['strictRegular']);
}
// prices
if (isset($data['priceKm'])) {
$ad->setPriceKm($data['priceKm']);
}
if (isset($data['outwardDriverPrice'])) {
$ad->setOutwardDriverPrice($data['outwardDriverPrice']);
}
if (isset($data['returnDriverPrice'])) {
$ad->setReturnDriverPrice($data['returnDriverPrice']);
}
if (isset($data['outwardPassengerPrice'])) {
$ad->setOutwardPassengerPrice($data['outwardPassengerPrice']);
}
if (isset($data['returnPassengerPrice'])) {
$ad->setReturnPassengerPrice($data['returnPassengerPrice']);
}
// seats
if (isset($data['seatsDriver'])) {
$ad->setSeatsDriver($data['seatsDriver']);
}
if (isset($data['seatsPassenger'])) {
$ad->setSeatsPassenger($data['seatsPassenger']);
}
// luggage
if (isset($data['luggage'])) {
$ad->setLuggage($data['luggage']);
}
// bike
if (isset($data['bike'])) {
$ad->setBike($data['bike']);
}
// backseats
if (isset($data['backSeats'])) {
$ad->setBackSeats($data['backSeats']);
}
// solidary
if (isset($data['solidary'])) {
$ad->setSolidary($data['solidary']);
}
// solidary exclusive
if (isset($data['solidaryExclusive'])) {
$ad->setSolidaryExclusive($data['solidaryExclusive']);
}
// avoid motorway
if (isset($data['avoidMotorway'])) {
$ad->setSolidary($data['avoidMotorway']);
}
// avoid toll
if (isset($data['avoidToll'])) {
$ad->setSolidary($data['avoidToll']);
}
// message
if (isset($data['message'])) {
$ad->setComment($data['message']);
}
// user
if (isset($data['userId'])) {
$ad->setUserId($data['userId']);
}
// we check if the ad is posted for another user (delegation)
if (isset($data['posterId'])) {
$ad->setPosterId($data['posterId']);
}
// communities
if (isset($data['communities'])) {
$ad->setCommunities($data['communities']);
}
// event
if (
(isset($data['origin']['event']['id']) && null != $data['origin']['event']['id'])
|| (isset($data['destination']['event']['id']) && null != $data['destination']['event']['id'])
) {
if (isset($data['origin']['event']['id']) && null != $data['origin']['event']['id']) {
$eventId = $data['origin']['event']['id'];
} elseif (isset($data['destination']['event']['id']) && null != $data['destination']['event']['id']) {
$eventId = $data['destination']['event']['id'];
}
$ad->setEventId($eventId);
}
if (isset($data['eventId'])) {
$ad->setEventId($data['eventId']);
}
// filters
if (isset($data['filters'])) {
$ad->setFilters($data['filters']);
}
if (isset($data['cancellationMessage'])) {
$ad->setCancellationMessage($data['cancellationMessage']);
}
if (isset($data['deletionMessage'])) {
$ad->setDeletionMessage($data['deletionMessage']);
}
if (isset($data['deleterId'])) {
$ad->setDeleterId($data['deleterId']);
}
return $ad;
}
public function cleanOrphanUserProposals()
{
$ad = new Ad();
if ($response = $this->dataProvider->post($ad, 'cleanOrphans')) {
return $response->getValue();
}
return null;
}
}