Validator/PublishStatusValidator.php
public function isExecutableByLocation($content, \DateTime $startDate)
    {
        $endDateInterval = clone $startDate;
        $endDateInterval->modify('+'.$this->maxDuplicateInterval);

        /*
         * If message contains no links, find out whether it has been posted before.
         */
        if($this->mustValidate($content, $startDate)){
            /*
             * Is the Activity supposed to be executed now or is it scheduled
             * within the time where a duplicate status error could emerge?
             */
            if(
                $this->schedulerUtil->isDueNow($startDate) ||
                ($startDate > new \DateTime() && $startDate < $endDateInterval)
            ) {
                // Connect to Facebook REST API
                /** @var FacebookClient $connection */
                $connection = $this->restClient->connectByActivity(
                    $content->getOperation()->getActivity()
                );

                try {
                    $response = $connection->getLatestPost($content->getFacebookLocation()->getIdentifier());
                } catch (\Exception $e) {
                    throw new ExternalApiException($e->getMessage(), $e->getCode(), $e);
                }

                if (
                    isset($response['data']) &&
                    isset($response['data'][0]) &&
                    // TODO: Extract URL at end of message to ensure exact match.
                    $response['data'][0]['message'] == $content->getMessage()
                ) {
                    return array(
                        'status' => false,
                        'message' =>
                            'Same message has already been posted as the latest one on Facebook: '
                            . '<a href="https://www.facebook.com/' . $response['data'][0]['id'] . '">'
                            . 'https://www.facebook.com/' . $response['data'][0]['id']
                            . '</a>. '
                            . 'Either change the message or leave at least '
                            . $this->maxDuplicateInterval.' between yours and the other post.'
                    );
                }
            } else {
                // Check if post with same content is scheduled for same Location.
                $newActivity = clone $content->getOperation()->getActivity();
                $newActivity->setStartDate($startDate);

                $closestActivities = array();

                $closestActivities[] = $this->em->getRepository('CampaignChainCoreBundle:Activity')
                    ->getClosestScheduledActivity($newActivity, '-'.$this->maxDuplicateInterval);
                $closestActivities[] = $this->em->getRepository('CampaignChainCoreBundle:Activity')
                    ->getClosestScheduledActivity($newActivity, '+'.$this->maxDuplicateInterval);

                foreach($closestActivities as $closestActivity) {
                    if ($closestActivity) {
                        $isUniqueContent = $this->isUniqueContent($closestActivity, $content);
                        if ($isUniqueContent['status'] == false) {
                            return $isUniqueContent;
                        }
                    }
                }
            }
        }

        return array(
            'status' => true,
        );
    }
public function isExecutableByLocation($content, \DateTime $startDate)
    {
        $endDateInterval = clone $startDate;
        $endDateInterval->modify('+'.$this->maxDuplicateInterval);

        /*
         * If message contains no links, find out whether it has been posted before.
         */
        if($this->mustValidate($content, $startDate)){
            /*
             * Is the Activity supposed to be executed now or is it scheduled
             * within the time where a duplicate status error could emerge?
             */
            if(
                $this->schedulerUtil->isDueNow($startDate) ||
                ($startDate > new \DateTime() && $startDate < $endDateInterval)
            ) {
                // Connect to Facebook REST API
                /** @var FacebookClient $connection */
                $connection = $this->restClient->connectByActivity(
                    $content->getOperation()->getActivity()
                );

                try {
                    $response = $connection->getLatestPost($content->getFacebookLocation()->getIdentifier());
                } catch (\Exception $e) {
                    throw new ExternalApiException($e->getMessage(), $e->getCode(), $e);
                }

                if (
                    isset($response['data']) &&
                    isset($response['data'][0]) &&
                    // TODO: Extract URL at end of message to ensure exact match.
                    $response['data'][0]['message'] == $content->getMessage()
                ) {
                    return array(
                        'status' => false,
                        'message' =>
                            'Same message has already been posted as the latest one on Facebook: '
                            . '<a href="https://www.facebook.com/' . $response['data'][0]['id'] . '">'
                            . 'https://www.facebook.com/' . $response['data'][0]['id']
                            . '</a>. '
                            . 'Either change the message or leave at least '
                            . $this->maxDuplicateInterval.' between yours and the other post.'
                    );
                }
            } else {
                // Check if post with same content is scheduled for same Location.
                $newActivity = clone $content->getOperation()->getActivity();
                $newActivity->setStartDate($startDate);

                $closestActivities = array();

                $closestActivities[] = $this->em->getRepository('CampaignChainCoreBundle:Activity')
                    ->getClosestScheduledActivity($newActivity, '-'.$this->maxDuplicateInterval);
                $closestActivities[] = $this->em->getRepository('CampaignChainCoreBundle:Activity')
                    ->getClosestScheduledActivity($newActivity, '+'.$this->maxDuplicateInterval);

                foreach($closestActivities as $closestActivity) {
                    if ($closestActivity) {
                        $isUniqueContent = $this->isUniqueContent($closestActivity, $content);
                        if ($isUniqueContent['status'] == false) {
                            return $isUniqueContent;
                        }
                    }
                }
            }
        }

        return array(
            'status' => true,
        );
    }
public function isExecutableByLocation ( $ content , \ DateTime $ startDate ) { $ endDateInterval = clone $ startDate ; $ endDateInterval -> modify ( '+' . $ this -> maxDuplicateInterval ) ; /*
         * If message contains no links, find out whether it has been posted before.
         */ if ( $ this -> mustValidate ( $ content , $ startDate ) ) { /*
             * Is the Activity supposed to be executed now or is it scheduled
             * within the time where a duplicate status error could emerge?
             */ if ( $ this -> schedulerUtil -> isDueNow ( $ startDate ) || ( $ startDate > new \ DateTime ( ) && $ startDate < $ endDateInterval ) ) { // Connect to Facebook REST API /** @var FacebookClient $connection */ $ connection = $ this -> restClient -> connectByActivity ( $ content -> getOperation ( ) -> getActivity ( ) ) ; try { $ response = $ connection -> getLatestPost ( $ content -> getFacebookLocation ( ) -> getIdentifier ( ) ) ; } catch ( \ Exception $ e ) { throw new ExternalApiException ( $ e -> getMessage ( ) , $ e -> getCode ( ) , $ e ) ; } if ( isset ( $ response [ 'data' ] ) && isset ( $ response [ 'data' ] [ 0 ] ) && // TODO: Extract URL at end of message to ensure exact match. $ response [ 'data' ] [ 0 ] [ 'message' ] == $ content -> getMessage ( ) ) { return array ( 'status' => false , 'message' => 'Same message has already been posted as the latest one on Facebook: ' . '<a href="https://www.facebook.com/' . $ response [ 'data' ] [ 0 ] [ 'id' ] . '">' . 'https://www.facebook.com/' . $ response [ 'data' ] [ 0 ] [ 'id' ] . '</a>. ' . 'Either change the message or leave at least ' . $ this -> maxDuplicateInterval . ' between yours and the other post.' ) ; } } else { // Check if post with same content is scheduled for same Location. $ newActivity = clone $ content -> getOperation ( ) -> getActivity ( ) ; $ newActivity -> setStartDate ( $ startDate ) ; $ closestActivities = array ( ) ; $ closestActivities [ ] = $ this -> em -> getRepository ( 'CampaignChainCoreBundle:Activity' ) -> getClosestScheduledActivity ( $ newActivity , '-' . $ this -> maxDuplicateInterval ) ; $ closestActivities [ ] = $ this -> em -> getRepository ( 'CampaignChainCoreBundle:Activity' ) -> getClosestScheduledActivity ( $ newActivity , '+' . $ this -> maxDuplicateInterval ) ; foreach ( $ closestActivities as $ closestActivity ) { if ( $ closestActivity ) { $ isUniqueContent = $ this -> isUniqueContent ( $ closestActivity , $ content ) ; if ( $ isUniqueContent [ 'status' ] == false ) { return $ isUniqueContent ; } } } } } return array ( 'status' => true , ) ; }
If the Activity is supposed to be executed now, we check whether there's
an identical post within the past 24 hours.

If it is a scheduled Activity, we check whether the are Activities
scheduled in the same Facebook Location within 24 hours prior or after
the new scheduled Activity contain the same text.

For now, this is a simplified implementation, not taking into account
the subtleties described below.

Here's what defines a duplicate message in Facebook:

A message is only a duplicate if it is identical with the latest post. If
a new post is identical with posts other than the latest, then it is not
a duplicate.

If the message contains at least one URL, then we're fine, because
we will create a unique shortened URL for each time the Facebook status
will be posted.

Note that Facebook allows to post identical content consecutively if it
includes shortened URLs (tested with Bit.ly). These shortened URLs can be
kept the same for each duplicate.

If the post contains a photo, the duplicate checks won't be applied by
Facebook.

@param StatusBase $content
@param \DateTime $startDate
@return array
If the Activity is supposed to be executed now we check whether there s an identical post within the past 24 hours .