Given a matching pattern and a contact, find any exceeded limits (aka caps/budgets).

@param ContactClient  $contactClient
@param array          $rules
@param null           $timezone
@param \DateTime|null $dateSend

@return array|null

@throws \Exception
4286
public function findLimit(
        ContactClient $contactClient,
        $rules = [],
        $timezone = null,
        \DateTime $dateSend = null
    ) {
        $filters = [];
        $result  = null;
        foreach ($rules as $rule) {
            $orx      = [];
            $value    = $rule['value'];
            $scope    = $rule['scope'];
            $duration = $rule['duration'];
            $quantity = $rule['quantity'];

            // Scope UTM Source
            if ($scope & self::SCOPE_UTM_SOURCE) {
                $utmSource = trim($value);
                if (!empty($utmSource)) {
                    $orx['utm_source'] = trim($value);
                }
            }

            // Scope Category
            if ($scope & self::SCOPE_CATEGORY) {
                $category = intval($value);
                if ($category) {
                    $orx['category_id'] = $category;
                }
            }

            // Match duration (always, including global scope)
            $filters[] = [
                'orx'              => $orx,
                'date_added'       => $this->oldestDateAdded($duration, $timezone, $dateSend)->getTimestamp(),
                'contactclient_id' => $contactClient->getId(),
            ];

            // Run the query to get the count.
            $count = $this->applyFilters($filters, true);
            if ($count > $quantity) {
                // Return the object, plus the count generated by the query.
                $result = [
                    'rule'  => $rule,
                    'count' => $count,
                ];
                break;
            }
        }

        return $result;
    }
758275
public function getEvents($contactSourceId, $eventType = null, \DateTime $dateAdded = null)
    {
        $q = $this->getEntityManager()->getConnection()->createQueryBuilder()
            ->from(MAUTIC_TABLE_PREFIX.'contactsource_events', 'c')
            ->select('c.*');

        $expr = $q->expr()->eq('c.contactsource_id', ':contactSource');
        $q->where($expr)
            ->setParameter('contactSource', (int) $contactSourceId);

        if ($dateAdded) {
            $expr->add(
                $q->expr()->gte('c.date_added', ':dateAdded')
            );
            $q->setParameter('dateAdded', $dateAdded);
        }

        if ($eventType) {
            $expr->add(
                $q->expr()->eq('c.type', ':type')
            );
            $q->setParameter('type', $eventType);
        }

        return $q->execute()->fetchAll();
    }
1335273
public function getContactEvents($contactId, $search = '', $start = 0, $limit = 0, $orderBy = '', $orderByDir = 'ASC')
    {
        $parameters = array(
            'search'        => $search,
            'start'         => $start,
            'limit'         => $limit,
            'orderBy'       => $orderBy,
            'orderByDir'    => $orderByDir,
        );

        $parameters = array_filter($parameters);

        return $this->makeRequest($this->endpoint.'/contact/'.$contactId, $parameters);
    }
29519
protected function getFormattedDate($input, $inputFormat, $outputFormat, DateTimeZone $timezone)
    {
        $formattedDate = DateTime::createFromFormat($inputFormat, $input, $timezone);
        if ($formattedDate) {
            return $formattedDate->format($outputFormat);
        }

        return $input;
    }
1255825
protected function performValidation(array $input, array $parsedRules, AppliesToResource $resource=null, $locale=null)
    {

        // First split rules into base rules and the custom rules of this class
        list($baseRules, $ownRules) = $this->toBaseAndOwnRules($parsedRules);

        $validation = new ValidationException();
        $validation->setRules($parsedRules);

        if ($baseRules) {
            $this->validateByBaseValidator($validation, $input, $baseRules, $resource, $locale);
        }

        if ($ownRules) {
            $this->validateByOwnMethods($validation, $input, $ownRules, $resource, $locale);
        }
        return $validation;
    }
79282
protected function getAllEngagements(
        array $contactClients,
        array $filters = null,
        array $orderBy = null,
        $page = 1,
        $limit = 25
    ) {
        $session = $this->get('session');

        if (null === $filters) {
            $chartfilters = $session->get(
                'mautic.contactclient.plugin.transactions.chartfilter',
                [
                    'date_from' => $this->get('mautic.helper.core_parameters')->getParameter(
                        'default_daterange_filter',
                        '-1 month'
                    ),
                    'date_to'   => null,
                    'type'      => 'All Events',
                ]
            );
            $session->set('mautic.contactclient.plugin.transactions.chartfilter');
            $search = $session->get('mautic.contactclient.plugin.transactions.search', '');
            $session->set('mautic.contactclient.plugin.transactions.search', '');
        }
        $filters = InputHelper::cleanArray(array_merge($chartfilters, ['search' => $search]));

        if (null == $orderBy) {
            if (!$session->has('mautic.contactclient.plugin.transactions.orderby')) {
                $session->set('mautic.contactclient.plugin.transactions.orderby', 'date_added');
                $session->set('mautic.contactclient.plugin.transactions.orderbydir', 'DESC');
            }

            $orderBy = [
                $session->get('mautic.contactclient.plugin.transactions.orderby'),
                $session->get('mautic.contactclient.plugin.transactions.orderbydir'),
            ];
        }

        // prepare result object
        $result = [
            'events'      => [],
            'chartfilter' => $chartfilters,
            'search'      => $search,
            'order'       => $orderBy,
            'types'       => [],
            'total'       => 0,
            'page'        => $page,
            'limit'       => $limit,
            'maxPages'    => 0,
        ];

        // get events for each contact
        foreach ($contactClients as $contactClient) {
            //  if (!$contactClient->getEmail()) continue; // discard contacts without email

            /** @var ContactClientModel $model */
            $model       = $this->getModel('contactClient');
            $engagements = $model->getEngagements($contactClient, $filters, $orderBy, $page, $limit);
            $events      = $engagements['events'];
            $types       = $engagements['types'];

            // inject contactClient into events
            foreach ($events as &$event) {
                $event['contactClientId']    = $contactClient->getId();
                $event['contactClientEmail'] = $contactClient->getEmail();
                $event['contactClientName']  = $contactClient->getName() ? $contactClient->getName(
                ) : $contactClient->getEmail();
            }

            $result['events'] = array_merge($result['events'], $events);
            $result['types']  = array_merge($result['types'], $types);
            $result['total'] += $engagements['total'];
        }

        $result['maxPages'] = ($limit <= 0) ? 1 : round(ceil($result['total'] / $limit));

        usort($result['events'], [$this, 'cmp']); // sort events by

        // now all events are merged, let's limit to   $limit
        array_splice($result['events'], $limit);

        $result['total'] = count($result['events']);

        return $result;
    }
193775
public function getContactCampaignEvents($campaignId, $contactId, $search = '', $start = 0, $limit = 0, $orderBy = '', $orderByDir = 'ASC')
    {
        $parameters = array(
            'search'        => $search,
            'start'         => $start,
            'limit'         => $limit,
            'orderBy'       => $orderBy,
            'orderByDir'    => $orderByDir,
        );

        $parameters = array_filter($parameters);

        return $this->makeRequest('campaigns/'.$campaignId.'/events/contact/'.$contactId, $parameters);
    }
528857
public function formatDateTime(\DateTime $datetime, $format, $calendar = \IntlDateFormatter::GREGORIAN)
    {
        $types = array(
            \IntlDateFormatter::NONE,
            \IntlDateFormatter::NONE,
        );
        if (is_array($format)) {
            if (isset($format[0])) {
                $types[0] = $format[0];
            }
            if (isset($format[1])) {
                $types[1] = $format[1];
            }
            $pattern = null;
        } else {
            $pattern = $format;
        }
        $formatter = new \IntlDateFormatter(
            $this->currentLocale,
            $types[0],
            $types[1],
            $datetime->getTimezone()->getName(),
            $calendar,
            $pattern
        );
        return $formatter->format($datetime);
    }
47904
public function evaluateLimits($limitRules = [], $campaignId = 0, $break = true, $name = true)
    {
        $limitRules = $this->mergeRules($limitRules, false);
        $limits     = $this->getRepository()->findLimits(
            $this->contactSource,
            $limitRules,
            $campaignId,
            $this->getTimezone(),
            $break,
            $name
        );
        if ($break) {
            foreach ($limits as $limit) {
                if (isset($limit['hit']) && true === $limit['hit']) {
                    throw new ContactSourceException(
                        'Cap exceeded'.!empty($limit['name']) ? ': '.$limit['name'] : '.',
                        Codes::HTTP_TOO_MANY_REQUESTS,
                        null,
                        Stat::TYPE_LIMITED,
                        false,
                        $limit
                    );
                }
            }
        }

        return $limits;
    }
316395
public function getContacts($limit = NULL, $offset = NULL) {
    $parameters = array();
    if (!empty($limit)) {
      $parameters['limit'] = $limit;
      if (!empty($offset)) {
        $parameters['offset'] = $offset;
      }
    }
    $data = $this->request('GET', 'contacts', $parameters);
    return $data->contacts;
  }
1365939
public function get($calendarId, $ruleId, $optParams = array()) {
      $params = array('calendarId' => $calendarId, 'ruleId' => $ruleId);
      $params = array_merge($params, $optParams);
      $data = $this->__call('get', array($params));
      if ($this->useObjects()) {
        return new AclRule($data);
      } else {
        return $data;
      }
    }
709157
protected function prepareRulesForValidation(array $rules, array $input, AppliesToResource $resource=null, $locale=null)
    {

        $preparedRules = [];
        $rules = parent::prepareRulesForValidation($rules, $input, $resource, $locale);

//        $dateConstraints = ['after', 'before', 'date'];

        // Flatify to allow nested checks
        $input = NestedArray::flat($input);

        foreach ($rules as $key=>$constraints) {

            $preparedRules[$key] = [];

            foreach ($constraints as $constraint=>$parameters) {

//                 if (in_array($constraint, $dateConstraints)) {
                    // Handle that later, we need complete localized formats
                    // to make this work (next EMS version)

//                 }

                if ($constraint == 'unique') {
                    $preparedRules[$key][$constraint] = $this->parametersOfUniqueConstraint($key, $parameters, $resource);
                    continue;
                }

                // required on an existing model should mean:
                // If the key isset, it should not contain any empty values
                // if not, the request is valid.
                // So just remove it if it shouldn't be updated
                if ($resource instanceof Entity && !$resource->isNew() && $constraint == 'required') {
                    if (!array_key_exists($key, $input)) {
                        continue;
                    }
                }

                $preparedRules[$key][$constraint] = $parameters;


            }

        }

        return $preparedRules;

    }
728746
private function evaluateFileRate($fileRate = 1, $date = null)
    {
        if (!$date) {
            $date = clone $this->now;
        }
        $date->setTimezone($this->timezone);
        $repo      = $this->getFileRepository();
        $fileCount = $repo->getCountByDate($date, $this->contactClient->getId());

        if ($fileCount >= $fileRate) {
            throw new ContactClientException(
                'This client has reached the maximum number of files they can receive per day.',
                0,
                null,
                Stat::TYPE_SCHEDULE,
                false
            );
        }

        return $fileCount;
    }
533739
public function getLimitRules()
    {
        $jsonHelper = new JSONHelper();
        $limits     = $jsonHelper->decodeObject($this->contactClient->getLimits(), 'Limits');

        $this->excludeIrrelevantRules($limits);

        return $this->mergeRules($limits, false);
    }
288090
public function getFiles(
        ContactClient $contactClient,
        array $filters = [],
        array $orderBy = [],
        $page = 1,
        $limit = 25
    ) {
        $args          = array_merge($filters, $orderBy);
        $args['page']  = $page;
        $args['limit'] = $limit;

        /** @var \MauticPlugin\MauticContactClientBundle\Entity\FileRepository $repo */
        $repo = $this->em->getRepository('MauticContactClientBundle:File');

        return $repo->getEntities($args);
    }
90381
private function createContact($apiClient, $customerEmail, $website, $contactFromTable)
    {
        $consentModel = $this->consentFactory->create();
        $consentData = $consentModel->getFormattedConsentDataByContactForApi(
            $website->getId(),
            $customerEmail
        );

        if (empty(! $consentData)) {
            $needToConfirm = $this->helper->getWebsiteConfig(
                \Magento\Newsletter\Model\Subscriber::XML_PATH_CONFIRMATION_FLAG,
                $website->getId()
            );
            $optInType = ($needToConfirm)? 'Double' : 'Single';
            $contactData = [
                'Email' => $customerEmail,
                'EmailType' => 'Html',
                'OptInType' => $optInType,
            ];

            $contact = $apiClient->postContactWithConsent(
                $contactData,
                $consentData
            );

        } else {
            $contact = $apiClient->postContacts(
                $customerEmail
            );
        }

        if (isset($contact->id)) {
            $contactFromTable->setContactId($contact->id);
            $this->helper->saveContact($contactFromTable);
        }

        return $contact;
    }
728225
public function getRouteCalendars($externalCoverageId, $externalRouteId, \DateTime $startDate, \DateTime $endDate)
    {
        $query = array(
            'api' => 'coverage',
            'parameters' => array(
                'region' => $externalCoverageId,
                'action' => 'calendars',
                'path_filter' => 'routes/'.$externalRouteId,
                'parameters' => '?start_date='.$startDate->format($this->dateFormat).'&end_date='.$endDate->format($this->dateFormat),
            ),
        );

        return $this->navitia_component->call($query);
    }