RebelCode/rcmod-eddbk-booking-logic

View on GitHub
src/BookingSessionValidator.php

Summary

Maintainability
A
0 mins
Test Coverage
<?php

namespace RebelCode\EddBookings\Logic\Module;

use Dhii\Expression\LogicalExpressionInterface;
use Dhii\Storage\Resource\SelectCapableInterface;
use Dhii\Util\Normalization\NormalizeIterableCapableTrait;
use Dhii\Validation\AbstractValidatorBase;
use RebelCode\Bookings\BookingInterface;

/**
 * A booking validator that validates whether a booking matches an existing session.
 *
 * @since [*next-version*]
 */
class BookingSessionValidator extends AbstractValidatorBase
{
    /* @since [*next-version*] */
    use NormalizeIterableCapableTrait;

    /**
     * The SELECT resource model for sessions.
     *
     * @since [*next-version*]
     *
     * @var SelectCapableInterface
     */
    protected $sessionsSelectRm;

    /**
     * The expression builder.
     *
     * @since [*next-version*]
     *
     * @var object
     */
    protected $exprBuilder;

    /**
     * Constructor.
     *
     * @since [*next-version*]
     *
     * @param SelectCapableInterface $sessionsSelectRm The SELECT resource model for sessions.
     * @param object                 $exprBuilder      The expression builder.
     */
    public function __construct($sessionsSelectRm, $exprBuilder)
    {
        $this->_setSessionsSelectRm($sessionsSelectRm);
        $this->_setExpressionBuilder($exprBuilder);
    }

    /**
     * Retrieves the sessions SELECT resource model.
     *
     * @since [*next-version*]
     *
     * @return SelectCapableInterface The sessions SELECT resource model instance.
     */
    protected function _getSessionsSelectRm()
    {
        return $this->sessionsSelectRm;
    }

    /**
     * Sets the sessions SELECT resource model.
     *
     * @since [*next-version*]
     *
     * @param SelectCapableInterface $sessionsSelectRm The sessions SELECT resource model instance.
     */
    protected function _setSessionsSelectRm($sessionsSelectRm)
    {
        if ($sessionsSelectRm !== null && !($sessionsSelectRm instanceof SelectCapableInterface)) {
            throw $this->_createInvalidArgumentException(
                $this->__('Argument is not a SELECT resource model'), null, null, $sessionsSelectRm
            );
        }

        $this->sessionsSelectRm = $sessionsSelectRm;
    }

    /**
     * Retrieves the expression builder.
     *
     * @since [*next-version*]
     *
     * @return object The expression builder instance.
     */
    protected function _getExpressionBuilder()
    {
        return $this->exprBuilder;
    }

    /**
     * Sets the expression builder.
     *
     * @since [*next-version*]
     *
     * @param object $exprBuilder The expression builder instance.
     */
    protected function _setExpressionBuilder($exprBuilder)
    {
        if (!is_object($exprBuilder)) {
            throw $this->_createInvalidArgumentException(
                $this->__('Argument is not an expression builder.'),
                null,
                null,
                $exprBuilder
            );
        }

        $this->exprBuilder = $exprBuilder;
    }

    /**
     * {@inheritdoc}
     *
     * @since [*next-version*]
     */
    protected function _getValidationErrors($booking)
    {
        if (!($booking instanceof BookingInterface)) {
            throw $this->_createInvalidArgumentException(
                $this->__('Subject is not a booking instance'), null, null, $booking
            );
        }

        $errors     = [];
        $condition  = $this->_buildBookingSessionCondition($booking);
        $matching   = $this->_getSessionsSelectRm()->select($condition);
        $numMatches = $this->_countIterable($matching);

        if ($numMatches === 0) {
            $errors[] = $this->__('The booking does not match any session');
        }

        return $errors;
    }

    /**
     * Builds the condition for retrieving the matching session for a booking.
     *
     * @since [*next-version*]
     *
     * @param BookingInterface $booking The booking instance for which to retrieve a matching session.
     *
     * @return LogicalExpressionInterface The condition.
     */
    protected function _buildBookingSessionCondition(BookingInterface $booking)
    {
        $b = $this->_getExpressionBuilder();

        $s1 = $b->lit($booking->getStart());
        $s2 = $b->ef('session', 'start');
        $e1 = $b->lit($booking->getEnd());
        $e2 = $b->ef('session', 'end');

        // Booking and session have identical start and end times
        $matchingTime = $b->and(
            $b->eq($s1, $s2),
            $b->eq($e1, $e2)
        );

        $matchingResource = null;
        foreach ($booking->getResourceIds() as $resourceId) {
            // The resource is in the list of resources for the session
            // The FIND_IN_SET(needle, haystack) MySQL function takes 2 strings and checks if the needle string
            // is found in the haystack string comma separated list (without whitespace).
            $r = $b->fn(
                'FIND_IN_SET',
                $b->lit($resourceId),
                $b->ef('session', 'resource_ids')
            );
            $matchingResource = ($matchingResource !== null)
                ? $b->and($matchingResource, $r)
                : $r;
        }

        return $b->and(
            $matchingTime,
            $matchingResource
        );
    }
}