public function clearIdentityMap($user = null)
    {
        if ($user === null) {
            $this->identityMap = array();
        } else if ($user instanceof User && array_key_exists($user->getId(), $this->identityMap)) {
            unset($this->identityMap[$user->getId()]);
        } else if (is_numeric($user) && array_key_exists($user, $this->identityMap)) {
            unset($this->identityMap[$user]);
        }
    }

public function clearIdentityMap ( $ user = null ) { if ( $ user === null ) { $ this -> identityMap = array ( ) ; } else if ( $ user instanceof User && array_key_exists ( $ user -> getId ( ) , $ this -> identityMap ) ) { unset ( $ this -> identityMap [ $ user -> getId ( ) ] ) ; } else if ( is_numeric ( $ user ) && array_key_exists ( $ user , $ this -> identityMap ) ) { unset ( $ this -> identityMap [ $ user ] ) ; } }

Clear User instances from the identity map, so that they can be read again from the database.

Call with no arguments to clear the entire identity map.
Pass a single user to remove just that user from the identity map.

@param mixed $user Either a User instance, an integer user ID, or null.

Clear User instances from the identity map so that they can be read again from the database .


public function loginAsUser(User $user)
    {
        if (null !== ($current_token = $this->app['security']->getToken())) {
            $providerKey = method_exists($current_token, 'getProviderKey') ? $current_token->getProviderKey() : $current_token->getKey();
            $token = new UsernamePasswordToken($user, null, $providerKey);
            $this->app['security']->setToken($token);

            $this->app['user'] = $user;
        }
    }

public function loginAsUser ( User $ user ) { if ( null !== ( $ current_token = $ this -> app [ 'security' ] -> getToken ( ) ) ) { $ providerKey = method_exists ( $ current_token , 'getProviderKey' ) ? $ current_token -> getProviderKey ( ) : $ current_token -> getKey ( ) ; $ token = new UsernamePasswordToken ( $ user , null , $ providerKey ) ; $ this -> app [ 'security' ] -> setToken ( $ token ) ; $ this -> app [ 'user' ] = $ user ; } }

Log in as the given user.

Sets the security token for the current request so it will be logged in as the given user.

@param User $user


private function init($force = false)
    {
        if (!function_exists('pcntl_signal') || ($this->initialized && !$force)) {
            return;
        }
        $this->initialized = true;
        pcntl_signal(SIGCHLD, array($this, 'signalHandler'));
    }

private function init ( $ force = false ) { if ( ! function_exists ( 'pcntl_signal' ) || ( $ this -> initialized && ! $ force ) ) { return ; } $ this -> initialized = true ; pcntl_signal ( SIGCHLD , array ( $ this , 'signalHandler' ) ) ; }

Initialize the signal handler.

Note: This will replace any current handler for SIGCHLD.

@param boolean $force Force initialization even if already initialized


public function reaper($pid = null, $status = null)
    {
        if ($pid === null) {
            $pid = pcntl_waitpid(-1, $status, WNOHANG);
        }

        while ($pid > 0) {
            if (isset($this->workers[$pid])) {
                // @todo does the socket really need to be closed?
                //@socket_close($this->workers[$pid]['socket']);
                unset($this->workers[$pid]);
            } else {
                // the child died before the parent could initialize the $worker
                // queue. So we track it temporarily so we can handle it in
                // self::create().
                $this->caught[$pid] = $status;
            }
            $pid = pcntl_waitpid(-1, $status, WNOHANG);
        }
    }


public function wait($timeout = null)
    {
        $x = null;                      // trash var needed for socket_select
        $startTime = microtime(true);
        while (true) {
            $this->apply();                         // maintain worker queue

            // check each child socket pair for a new result
            $read = array_map(function($w){ return $w['socket']; }, $this->workers);
            // it's possible for no workers/sockets to be present due to REAPING
            if (!empty($read)) {
                $ok = @socket_select($read, $x, $x, $timeout);
                if ($ok !== false and $ok > 0) {
                    return $read;
                }
            }

            // timed out?
            if ($timeout and microtime(true) - $startTime > $timeout) {
                return null;
            }

            // no sense in waiting if we have no workers and no more pending
            if (empty($this->workers) and empty($this->pending)) {
                return null;
            }
        }
    }

Wait for any child to be ready

@param integer $timeout Timeout to wait (fractional seconds)
@return array|null Returns array of sockets ready to be READ or null


public function get($timeout = null, $nullOnTimeout = false)
    {
        $startTime = microtime(true);
        while ($this->getPending()) {
            // return the next result
            if ($this->hasResult()) {
                return $this->getResult();
            }

            // wait for the next result
            $ready = $this->wait($timeout);
            if (is_array($ready)) {
                foreach ($ready as $socket) {
                    $res = self::socket_fetch($socket);
                    if ($res !== null) {
                        $this->results[] = $res;
                        $this->count++;
                    }
                }
                if ($this->hasResult()) {
                    return $this->getResult();
                }
            }

            // timed out?
            if ($timeout and microtime(true) - $startTime > $timeout) {
                if ($nullOnTimeout) {
                    return null;
                }
                throw new ProcessPoolException("Timeout");
            }
        }
    }

public
function
get
(
$
timeout
=
,
$
nullOnTimeout
=
false
)
{
$
startTime
=
microtime
(
true
)
;
while
(
$
this
->
getPending
(
)
)
{
// return the next result
if
(
$
this
->
hasResult
(
)
)
{
return
$
this
->
getResult
(
)
;
}
// wait for the next result
$
ready
=
$
this
->
wait
(
$
timeout
)
;
if
(
is_array
(
$
ready
)
)
{
foreach
(
$
ready
as
$
socket
)
{
$
res
=
self
::
socket_fetch
(
$
socket
)
;
if
(
$
res
!==
)
{
$
this
->
results
[
]
=
$
res
;
$
this
->
count
++
;
}
}
if
(
$
this
->
hasResult
(
)
)
{
return
$
this
->
getResult
(
)
;
}
}
// timed out?
if
(
$
timeout
and
microtime
(
true
)
$
startTime
>
$
timeout
)
{
if
(
$
nullOnTimeout
)
{
return
;
}
throw
new
ProcessPoolException
(
"Timeout"
)
;
}
}
}

Return the next available result.

Blocks unless a $timeout is specified.

@param integer $timeout Timeout in fractional seconds if no results are available.
@return mixed Returns next child response or null on timeout
@throws ProcessPoolException On timeout if $nullOnTimeout is false


public function getAll($timeout = null, $nullOnTimeout = false)
    {
        $results = array();
        $startTime = microtime(true);
        while ($this->getPending()) {
            try {
                $res = $this->get($timeout);
                if ($res !== null) {
                    $results[] = $res;
                }
            } catch (ProcessPoolException $e) {
                // timed out
            }

            // timed out?
            if ($timeout and microtime(true) - $startTime > $timeout) {
                if ($nullOnTimeout) {
                    return null;
                }
                throw new ProcessPoolException("Timeout");
            }
        }
        return $results;
    }

public
function
getAll
(
$
timeout
=
,
$
nullOnTimeout
=
false
)
{
$
results
=
array
(
)
;
$
startTime
=
microtime
(
true
)
;
while
(
$
this
->
getPending
(
)
)
{
try
{
$
res
=
$
this
->
get
(
$
timeout
)
;
if
(
$
res
!==
)
{
$
results
[
]
=
$
res
;
}
}
catch
(
ProcessPoolException
$
e
)
{
// timed out
}
// timed out?
if
(
$
timeout
and
microtime
(
true
)
$
startTime
>
$
timeout
)
{
if
(
$
nullOnTimeout
)
{
return
;
}
throw
new
ProcessPoolException
(
"Timeout"
)
;
}
}
return
$
results
;
}

Return results from all workers.

Does not return until all pending workers are complete or the $timeout
is reached.

@param integer $timeout Timeout in fractional seconds if no results are available.
@return array Returns an array of results
@throws ProcessPoolException On timeout if $nullOnTimeout is false


public function apply($func = null)
    {
        // add new function to pending queue
        if ($func !== null) {
            if ($func instanceof \Closure or $func instanceof ProcessInterface or is_callable($func)) {
                $this->pending[] = func_get_args();
            } else {
                throw new \UnexpectedValueException("Parameter 1 in ProcessPool#apply must be a Closure or callable");
            }
        }

        // start a new worker if our current worker queue is low
        if (!empty($this->pending) and count($this->workers) < $this->max) {
            call_user_func_array(array($this, 'create'), array_shift($this->pending));
        }

        return $this;
    }

Apply a worker to the working or pending queue

@param Callable $func Callback function to fork into.
@return ProcessPool


public function getPending($pendingOnly = false)
    {
        if ($pendingOnly) {
            return count($this->pending);
        }
        return count($this->pending) + count($this->workers) + count($this->results);
    }

public function getPending ( $ pendingOnly = false ) { if ( $ pendingOnly ) { return count ( $ this -> pending ) ; } return count ( $ this -> pending ) + count ( $ this -> workers ) + count ( $ this -> results ) ; }

Return the total jobs that have NOT completed yet.

Return the total jobs that have NOT completed yet .


public static function socket_send($socket, $data)
    {
        $serialized = serialize($data);
        $hdr = pack('N', strlen($serialized));    // 4 byte length
        $buffer = $hdr . $serialized;
        $total = strlen($buffer);
        while (true) {
            $sent = socket_write($socket, $buffer);
            if ($sent === false) {
                // @todo handle error?
                //$error = socket_strerror(socket_last_error());
                break;
            }
            if ($sent >= $total) {
                break;
            }
            $total -= $sent;
            $buffer = substr($buffer, $sent);
        }
    }

Write the data to the socket in a predetermined format


public static function socket_fetch($socket)
    {
        // read 4 byte length first
        $hdr = '';
        do {
            $read = socket_read($socket, 4 - strlen($hdr));
            if ($read === false or $read === '') {
                return null;
            }
            $hdr .= $read;
        } while (strlen($hdr) < 4);

        list($len) = array_values(unpack("N", $hdr));

        // read the full buffer
        $buffer = '';
        do {
            $read = socket_read($socket, $len - strlen($buffer));
            if ($read === false or $read == '') {
                return null;
            }
            $buffer .= $read;
        } while (strlen($buffer) < $len);

        $data = unserialize($buffer);
        return $data;
    }

public
static
function
socket_fetch
(
$
socket
)
{
// read 4 byte length first
$
hdr
=
''
;
do
{
$
read
=
socket_read
(
$
socket
,
4
strlen
(
$
hdr
)
)
;
if
(
$
read
===
false
or
$
read
===
''
)
{
return
;
}
$
hdr
.=
$
read
;
}
while
(
strlen
(
$
hdr
)
<
4
)
;
list
(
$
len
)
=
array_values
(
unpack
(
"N"
,
$
hdr
)
)
;
// read the full buffer
$
buffer
=
''
;
do
{
$
read
=
socket_read
(
$
socket
,
$
len
strlen
(
$
buffer
)
)
;
if
(
$
read
===
false
or
$
read
==
''
)
{
return
;
}
$
buffer
.=
$
read
;
}
while
(
strlen
(
$
buffer
)
<
$
len
)
;
$
data
=
unserialize
(
$
buffer
)
;
return
$
data
;
}

Read a data packet from the socket in a predetermined format.

Blocking.

Read a data packet from the socket in a predetermined format .


public function sqlDownData()
    {
        // Map columns to custom fields.
        $colmap = array();
        foreach ($this->fieldmap as $field => $col) {
            $colmap[$col] = $field;
        }

        // Test that the v2 columns actually exist.
        $existingCols = $this->conn->getSchemaManager()->listTableColumns($this->usersTable);
        $existingColnames = array_map(function($col) { return $col->getName(); }, $existingCols);
        foreach ($this->fieldmap as $col) {
            if (!in_array($col, $existingColnames)) {
                throw new \RuntimeException('Cannot migrate down because current schema is not v2. (Missing column "' . $this->usersTable . '.' . $col . '").');
            }
        }

        // Get user columns to revert back to custom fields.
        $userData = $this->conn->fetchAll('SELECT id AS user_id, ' . implode(', ', $this->fieldmap) . ' FROM ' . $this->conn->quoteIdentifier($this->usersTable));

        $queries = array();
        foreach ($userData as $row) {
            foreach ($this->fieldmap as $col) {
                if ($row[$col] !== null) {
                    $queries[] = 'INSERT INTO ' . $this->conn->quoteIdentifier($this->userCustomFieldsTable)
                        . ' (user_id, attribute, value) VALUES'
                        . ' (' . $this->conn->quote($row['user_id'], Type::INTEGER)
                        . ', ' . $this->conn->quote($colmap[$col], Type::STRING)
                        . ', ' . $this->conn->quote($row[$col], Type::STRING)
                        . ')';
                }
            }

        }

        return $queries;
    }


public function registerAction(Application $app, Request $request)
    {
        if ($request->isMethod('POST')) {
            try {
                $user = $this->createUserFromRequest($request);
                if ($error = $this->userManager->validatePasswordStrength($user, $request->request->get('password'))) {
                    throw new InvalidArgumentException($error);
                }
                if ($this->isEmailConfirmationRequired) {
                    $user->setEnabled(false);
                    $user->setConfirmationToken($app['user.tokenGenerator']->generateToken());
                }
                $this->userManager->insert($user);

                if ($this->isEmailConfirmationRequired) {
                    // Send email confirmation.
                    $app['user.mailer']->sendConfirmationMessage($user);

                    // Render the "go check your email" page.
                    return $app['twig']->render($this->getTemplate('register-confirmation-sent'), array(
                        'layout_template' => $this->getTemplate('layout'),
                        'email' => $user->getEmail(),
                    ));
                } else {
                    // Log the user in to the new account.
                    $this->userManager->loginAsUser($user);

                    $app['session']->getFlashBag()->set('alert', 'Account created.');

                    // Redirect to user's new profile page.
                    return $app->redirect($app['url_generator']->generate('user.view', array('id' => $user->getId())));
                }

            } catch (InvalidArgumentException $e) {
                $error = $e->getMessage();
            }
        }

        return $app['twig']->render($this->getTemplate('register'), array(
            'layout_template' => $this->getTemplate('layout'),
            'error' => isset($error) ? $error : null,
            'name' => $request->request->get('name'),
            'email' => $request->request->get('email'),
            'username' => $request->request->get('username'),
            'isUsernameRequired' => $this->isUsernameRequired,
        ));
    }

Register action.

@param Application $app
@param Request $request
@return Response


public function confirmEmailAction(Application $app, Request $request, $token)
    {
        $user = $this->userManager->findOneBy(array('confirmationToken' => $token));
        if (!$user) {
            $app['session']->getFlashBag()->set('alert', 'Sorry, your email confirmation link has expired.');

            return $app->redirect($app['url_generator']->generate('user.login'));
        }

        $user->setConfirmationToken(null);
        $user->setEnabled(true);
        $this->userManager->update($user);

        $this->userManager->loginAsUser($user);

        $app['session']->getFlashBag()->set('alert', 'Thank you! Your account has been activated.');

        return $app->redirect($app['url_generator']->generate('user.view', array('id' => $user->getId())));
    }

Action to handle email confirmation links.

@param Application $app
@param Request $request
@param string $token
@return \Symfony\Component\HttpFoundation\RedirectResponse
@throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException

Action to handle email confirmation links .


public function loginAction(Application $app, Request $request)
    {
        $authException = $app['user.last_auth_exception']($request);

        if ($authException instanceof DisabledException) {
            // This exception is thrown if (!$user->isEnabled())
            // Warning: Be careful not to disclose any user information besides the email address at this point.
            // The Security system throws this exception before actually checking if the password was valid.
            $user = $this->userManager->refreshUser($authException->getUser());

            return $app['twig']->render($this->getTemplate('login-confirmation-needed'), array(
                'layout_template' => $this->getTemplate('layout'),
                'email' => $user->getEmail(),
                'fromAddress' => $app['user.mailer']->getFromAddress(),
                'resendUrl' => $app['url_generator']->generate('user.resend-confirmation'),
            ));
        }

        return $app['twig']->render($this->getTemplate('login'), array(
            'layout_template' => $this->getTemplate('layout'),
            'error' => $authException ? $authException->getMessageKey() : null,
            'last_username' => $app['session']->get('_security.last_username'),
            'allowRememberMe' => isset($app['security.remember_me.response_listener']),
            'allowPasswordReset' => $this->isPasswordResetEnabled(),
        ));
    }

Login action.

@param Application $app
@param Request $request
@return Response


public function resendConfirmationAction(Application $app, Request $request)
    {
        $email = $request->request->get('email');
        $user = $this->userManager->findOneBy(array('email' => $email));
        if (!$user) {
            throw new NotFoundHttpException('No user account was found with that email address.');
        }

        if (!$user->getConfirmationToken()) {
            $user->setConfirmationToken($app['user.tokenGenerator']->generateToken());
            $this->userManager->update($user);
        }

        $app['user.mailer']->sendConfirmationMessage($user);

        // Render the "go check your email" page.
        return $app['twig']->render($this->getTemplate('register-confirmation-sent'), array(
            'layout_template' => $this->getTemplate('layout'),
            'email' => $user->getEmail(),
        ));
    }

Action to resend an email confirmation message.

@param Application $app
@param Request $request
@return mixed
@throws \Symfony\Component\HttpKernel\Exception\NotFoundHttpException

Action to resend an email confirmation message .


public function viewAction(Application $app, Request $request, $id)
    {
        $user = $this->userManager->getUser($id);

        if (!$user) {
            throw new NotFoundHttpException('No user was found with that ID.');
        }

        if (!$user->isEnabled() && !$app['security']->isGranted('ROLE_ADMIN')) {
            throw new NotFoundHttpException('That user is disabled (pending email confirmation).');
        }

        return $app['twig']->render($this->getTemplate('view'), array(
            'layout_template' => $this->getTemplate('layout'),
            'user' => $user,
            'imageUrl' => $this->getGravatarUrl($user->getEmail()),
        ));

    }

View user action.

@param Application $app
@param Request $request
@param int $id
@return Response
@throws NotFoundHttpException if no user is found with that ID.


public function editAction(Application $app, Request $request, $id)
    {
        $errors = array();

        $user = $this->userManager->getUser($id);
        if (!$user) {
            throw new NotFoundHttpException('No user was found with that ID.');
        }

        $customFields = $this->editCustomFields ?: array();

        if ($request->isMethod('POST')) {
            $user->setName($request->request->get('name'));
            $user->setEmail($request->request->get('email'));
            if ($request->request->has('username')) {
                $user->setUsername($request->request->get('username'));
            }
            if ($request->request->get('password')) {
                if ($request->request->get('password') != $request->request->get('confirm_password')) {
                    $errors['password'] = 'Passwords don\'t match.';
                } else if ($error = $this->userManager->validatePasswordStrength($user, $request->request->get('password'))) {
                    $errors['password'] = $error;
                } else {
                    $this->userManager->setUserPassword($user, $request->request->get('password'));
                }
            }
            if ($app['security']->isGranted('ROLE_ADMIN') && $request->request->has('roles')) {
                $user->setRoles($request->request->get('roles'));
            }

            foreach (array_keys($customFields) as $customField) {
                if ($request->request->has($customField)) {
                    $user->setCustomField($customField, $request->request->get($customField));
                }
            }

            $errors += $this->userManager->validate($user);

            if (empty($errors)) {
                $this->userManager->update($user);
                $msg = 'Saved account information.' . ($request->request->get('password') ? ' Changed password.' : '');
                $app['session']->getFlashBag()->set('alert', $msg);
            }
        }

        return $app['twig']->render($this->getTemplate('edit'), array(
            'layout_template' => $this->getTemplate('layout'),
            'error' => implode("\n", $errors),
            'user' => $user,
            'available_roles' => array('ROLE_USER', 'ROLE_ADMIN'),
            'image_url' => $this->getGravatarUrl($user->getEmail()),
            'customFields' => $customFields,
            'isUsernameRequired' => $this->isUsernameRequired,
        ));
    }

public
function
editAction
(
Application
$
app
,
Request
$
request
,
$
id
)
{
$
errors
=
array
(
)
;
$
user
=
$
this
->
userManager
->
getUser
(
$
id
)
;
if
(
!
$
user
)
{
throw
new
NotFoundHttpException
(
'No user was found with that ID.'
)
;
}
$
customFields
=
$
this
->
editCustomFields
:
array
(
)
;
if
(
$
request
->
isMethod
(
'POST'
)
)
{
$
user
->
setName
(
$
request
->
request
->
get
(
'name'
)
)
;
$
user
->
setEmail
(
$
request
->
request
->
get
(
'email'
)
)
;
if
(
$
request
->
request
->
has
(
'username'
)
)
{
$
user
->
setUsername
(
$
request
->
request
->
get
(
'username'
)
)
;
}
if
(
$
request
->
request
->
get
(
'password'
)
)
{
if
(
$
request
->
request
->
get
(
'password'
)
!=
$
request
->
request
->
get
(
'confirm_password'
)
)
{
$
errors
[
'password'
]
=
'Passwords don\'t match.'
;
}
else
if
(
$
error
=
$
this
->
userManager
->
validatePasswordStrength
(
$
user
,
$
request
->
request
->
get
(
'password'
)
)
)
{
$
errors
[
'password'
]
=
$
error
;
}
else
{
$
this
->
userManager
->
setUserPassword
(
$
user
,
$
request
->
request
->
get
(
'password'
)
)
;
}
}
if
(
$
app
[
'security'
]
->
isGranted
(
'ROLE_ADMIN'
)
&&
$
request
->
request
->
has
(
'roles'
)
)
{
$
user
->
setRoles
(
$
request
->
request
->
get
(
'roles'
)
)
;
}
foreach
(
array_keys
(
$
customFields
)
as
$
customField
)
{
if
(
$
request
->
request
->
has
(
$
customField
)
)
{
$
user
->
setCustomField
(
$
customField
,
$
request
->
request
->
get
(
$
customField
)
)
;
}
}
$
errors
+=
$
this
->
userManager
->
validate
(
$
user
)
;
if
(
empty
(
$
errors
)
)
{
$
this
->
userManager
->
update
(
$
user
)
;
$
msg
=
'Saved account information.'
.
(
$
request
->
request
->
get
(
'password'
)
' Changed password.'
:
''
)
;
$
app
[
'session'
]
->
getFlashBag
(
)
->
set
(
'alert'
,
$
msg
)
;
}
}
return
$
app
[
'twig'
]
->
render
(
$
this
->
getTemplate
(
'edit'
)
,
array
(
'layout_template'
=>
$
this
->
getTemplate
(
'layout'
)
,
'error'
=>
implode
(
"\n"
,
$
errors
)
,
'user'
=>
$
user
,
'available_roles'
=>
array
(
'ROLE_USER'
,
'ROLE_ADMIN'
)
,
'image_url'
=>
$
this
->
getGravatarUrl
(
$
user
->
getEmail
(
)
)
,
'customFields'
=>
$
customFields
,
'isUsernameRequired'
=>
$
this
->
isUsernameRequired
,
)
)
;
}

Edit user action.

@param Application $app
@param Request $request
@param int $id
@return Response
@throws NotFoundHttpException if no user is found with that ID.


public function validate()
    {
        $errors = array();

        if (!$this->getEmail()) {
            $errors['email'] = 'Email address is required.';
        } else if (!strpos($this->getEmail(), '@')) {
            // Basic email format sanity check. Real validation comes from sending them an email with a link they have to click.
            $errors['email'] = 'Email address appears to be invalid.';
        } else if (strlen($this->getEmail()) > 100) {
            $errors['email'] = 'Email address can\'t be longer than 100 characters.';
        }

        if (!$this->getPassword()) {
            $errors['password'] = 'Password is required.';
        } else if (strlen($this->getPassword()) > 255) {
            $errors['password'] = 'Password can\'t be longer than 255 characters.';
        }

        if (strlen($this->getName()) > 100) {
            $errors['name'] = 'Name can\'t be longer than 100 characters.';
        }

        // Username can't contain "@",
        // because that's how we distinguish between email and username when signing in.
        // (It's possible to sign in by providing either one.)
        if ($this->getRealUsername() && strpos($this->getRealUsername(), '@') !== false) {
            $errors['username'] = 'Username cannot contain the "@" symbol.';
        }

        return $errors;
    }

Validate the user object.

@return array An array of error messages, or an empty array if there were no errors.


public function connect(Application $app)
    {
        if (!$app['resolver'] instanceof ServiceControllerResolver) {
            // using RuntimeException crashes PHP?!
            throw new \LogicException('You must enable the ServiceController service provider to be able to use these routes.');
        }

        /** @var ControllerCollection $controllers */
        $controllers = $app['controllers_factory'];

        $controllers->get('/', 'user.controller:viewSelfAction')
            ->bind('user')
            ->before(function(Request $request) use ($app) {
                // Require login. This should never actually cause access to be denied,
                // but it causes a login form to be rendered if the viewer is not logged in.
                if (!$app['user']) {
                    throw new AccessDeniedException();
                }
            });

        $controllers->get('/{id}', 'user.controller:viewAction')
            ->bind('user.view')
            ->assert('id', '\d+');

        $controllers->method('GET|POST')->match('/{id}/edit', 'user.controller:editAction')
            ->bind('user.edit')
            ->before(function(Request $request) use ($app) {
                if (!$app['security']->isGranted('EDIT_USER_ID', $request->get('id'))) {
                    throw new AccessDeniedException();
                }
            });

        $controllers->get('/list', 'user.controller:listAction')
            ->bind('user.list');

        $controllers->method('GET|POST')->match('/register', 'user.controller:registerAction')
            ->bind('user.register');

        $controllers->get('/confirm-email/{token}', 'user.controller:confirmEmailAction')
            ->bind('user.confirm-email');

        $controllers->post('/resend-confirmation', 'user.controller:resendConfirmationAction')
            ->bind('user.resend-confirmation');

        $controllers->get('/login', 'user.controller:loginAction')
            ->bind('user.login');

        $controllers->method('GET|POST')->match('/forgot-password', 'user.controller:forgotPasswordAction')
            ->bind('user.forgot-password');

        $controllers->get('/reset-password/{token}', 'user.controller:resetPasswordAction')
            ->bind('user.reset-password');

        // login_check and logout are dummy routes so we can use the names.
        // The security provider should intercept these, so no controller is needed.
        $controllers->method('GET|POST')->match('/login_check', function() {})
            ->bind('user.login_check');
        $controllers->get('/logout', function() {})
            ->bind('user.logout');

        return $controllers;
    }

Returns routes to connect to the given application.

@param Application $app An Application instance

@return ControllerCollection A ControllerCollection instance
@throws \LogicException if ServiceController service provider is not registered.

Returns routes to connect to the given application .


protected function priorities()
    {
        $priorities = [];

        foreach ($this as $formatter => $quality) {
            foreach ($formatter::accepts() as $type) {
                $priorities[$type] = $formatter;
            }
        }

        return $priorities;
    }

protected function priorities ( ) { $ priorities = [ ] ; foreach ( $ this as $ formatter => $ quality ) { foreach ( $ formatter :: accepts ( ) as $ type ) { $ priorities [ $ type ] = $ formatter ; } } return $ priorities ; }

Retrieve a map of accepted priorities with the responsible formatter.

@return array

Retrieve a map of accepted priorities with the responsible formatter .


protected function formatter(ServerRequestInterface $request)
    {
        $accept = $request->getHeaderLine('Accept');
        $priorities = $this->priorities();

        if (!empty($accept)) {
            $preferred = $this->negotiator->getBest($accept, array_keys($priorities));
        }

        if (!empty($preferred)) {
            $formatter = $priorities[$preferred->getValue()];
        } else {
            $formatter = array_shift($priorities);
        }

        return $this->resolve($formatter);
    }

protected function formatter ( ServerRequestInterface $ request ) { $ accept = $ request -> getHeaderLine ( 'Accept' ) ; $ priorities = $ this -> priorities ( ) ; if ( ! empty ( $ accept ) ) { $ preferred = $ this -> negotiator -> getBest ( $ accept , array_keys ( $ priorities ) ) ; } if ( ! empty ( $ preferred ) ) { $ formatter = $ priorities [ $ preferred -> getValue ( ) ] ; } else { $ formatter = array_shift ( $ priorities ) ; } return $ this -> resolve ( $ formatter ) ; }

Retrieve the formatter to use for the current request.

Uses content negotiation to find the best available output format for
the requested content type.

@param ServerRequestInterface $request

@return FormatterInterface

Retrieve the formatter to use for the current request .


protected function format(
        ServerRequestInterface $request,
        ResponseInterface $response,
        PayloadInterface $payload
    ) {
        $formatter = $this->formatter($request);

        $response = $response->withHeader('Content-Type', $formatter->type());
        // Overwrite the body instead of making a copy and dealing with the stream.
        $response->getBody()->write($formatter->body($payload));

        return $response;
    }

Update the response by formatting the payload.

@param ServerRequestInterface $request
@param ResponseInterface $response
@param PayloadInterface $payload

@return ResponseInterface

Update the response by formatting the payload .


private function detectEnvFile()
    {
        $env = DIRECTORY_SEPARATOR . '.env';
        $dir = dirname(dirname(__DIR__));

        do {
            if (is_file($dir . $env)) {
                return $dir . $env;
            }
            $dir = dirname($dir);
        } while (is_readable($dir) && dirname($dir) !== $dir);

        throw EnvException::detectionFailed();
    }

private function detectEnvFile ( ) { $ env = DIRECTORY_SEPARATOR . '.env' ; $ dir = dirname ( dirname ( __DIR__ ) ) ; do { if ( is_file ( $ dir . $ env ) ) { return $ dir . $ env ; } $ dir = dirname ( $ dir ) ; } while ( is_readable ( $ dir ) && dirname ( $ dir ) !== $ dir ) ; throw EnvException :: detectionFailed ( ) ; }

Find a .env file by traversing up the filesystem

@return string

@throws EnvException If no file is found

Find a . env file by traversing up the filesystem


private function type(ServerRequestInterface $request)
    {
        $accept = $request->getHeaderLine('Accept');
        $priorities = $this->preferences->toArray();

        if (!empty($accept)) {
            $preferred = $this->negotiator->getBest($accept, array_keys($priorities));
        }

        if (!empty($preferred)) {
            return $preferred->getValue();
        }

        return key($priorities);
    }

private function type ( ServerRequestInterface $ request ) { $ accept = $ request -> getHeaderLine ( 'Accept' ) ; $ priorities = $ this -> preferences -> toArray ( ) ; if ( ! empty ( $ accept ) ) { $ preferred = $ this -> negotiator -> getBest ( $ accept , array_keys ( $ priorities ) ) ; } if ( ! empty ( $ preferred ) ) { return $ preferred -> getValue ( ) ; } return key ( $ priorities ) ; }

Determine the preferred content type for the current request

@param ServerRequestInterface $request

@return string


public static function build(
        Injector $injector = null,
        ConfigurationSet $configuration = null,
        MiddlewareSet $middleware = null
    ) {
        return new static($injector, $configuration, $middleware);
    }

public static function build ( Injector $ injector = null , ConfigurationSet $ configuration = null , MiddlewareSet $ middleware = null ) { return new static ( $ injector , $ configuration , $ middleware ) ; }

Create a new application

@param Injector $injector
@param ConfigurationSet $configuration
@param MiddlewareSet $middleware

@return static


public function run($runner = Relay::class)
    {
        $this->configuration->apply($this->injector);

        return $this->injector
            ->share($this->middleware)
            ->prepare(Directory::class, $this->routing)
            ->execute($runner);
    }

public function run ( $ runner = Relay :: class ) { $ this -> configuration -> apply ( $ this -> injector ) ; return $ this -> injector -> share ( $ this -> middleware ) -> prepare ( Directory :: class , $ this -> routing ) -> execute ( $ runner ) ; }

Run the application

@param string $runner

@return \Psr\Http\Message\ResponseInterface


private function handle(
        Action $action,
        ServerRequestInterface $request,
        ResponseInterface $response
    ) {
        $domain = $this->resolve($action->getDomain());
        $input = $this->resolve($action->getInput());
        $responder = $this->resolve($action->getResponder());

        $payload = $this->payload($domain, $input, $request);
        $response = $this->response($responder, $request, $response, $payload);

        return $response;
    }

private function handle ( Action $ action , ServerRequestInterface $ request , ResponseInterface $ response ) { $ domain = $ this -> resolve ( $ action -> getDomain ( ) ) ; $ input = $ this -> resolve ( $ action -> getInput ( ) ) ; $ responder = $ this -> resolve ( $ action -> getResponder ( ) ) ; $ payload = $ this -> payload ( $ domain , $ input , $ request ) ; $ response = $ this -> response ( $ responder , $ request , $ response , $ payload ) ; return $ response ; }

Use the action collaborators to get a response.

@param Action $action
@param ServerRequestInterface $request
@param ResponseInterface $response

@return ResponseInterface

Use the action collaborators to get a response .


private function payload(
        DomainInterface $domain,
        InputInterface $input,
        ServerRequestInterface $request
    ) {
        return $domain($input($request));
    }

private function payload ( DomainInterface $ domain , InputInterface $ input , ServerRequestInterface $ request ) { return $ domain ( $ input ( $ request ) ) ; }

Execute the domain to get a payload using input from the request.

@param DomainInterface $domain
@param InputInterface $input
@param ServerRequestInterface $request

@return PayloadInterface

Execute the domain to get a payload using input from the request .


private function response(
        ResponderInterface $responder,
        ServerRequestInterface $request,
        ResponseInterface $response,
        PayloadInterface $payload
    ) {
        return $responder($request, $response, $payload);
    }

private function response ( ResponderInterface $ responder , ServerRequestInterface $ request , ResponseInterface $ response , PayloadInterface $ payload ) { return $ responder ( $ request , $ response , $ payload ) ; }

Execute the responder to marshall the payload into the response.

@param ResponderInterface $responder
@param ServerRequestInterface $request
@param ResponseInterface $response
@param PayloadInterface $payload

@return ResponseInterface

Execute the responder to marshall the payload into the response .


private function status(
        ResponseInterface $response,
        PayloadInterface $payload
    ) {
        $status = $payload->getStatus();
        $code = $this->http_status->getStatusCode($status);

        return $response->withStatus($code);
    }

private function status ( ResponseInterface $ response , PayloadInterface $ payload ) { $ status = $ payload -> getStatus ( ) ; $ code = $ this -> http_status -> getStatusCode ( $ status ) ; return $ response -> withStatus ( $ code ) ; }

Get the response with the status code from the payload.

@param ResponseInterface $response
@param PayloadInterface $payload

@return ResponseInterface

Get the response with the status code from the payload .


public function getCommandFromResource($resource, $action, $relation = null)
    {
        $namespace = Config::get('api.app_namespace');
        $mapping = Config::get('api.mapping');

        // If the mapping does not exist, we consider this as a 404 error
        if (!isset($mapping[$resource])) {
            throw new NotFoundHttpException('The resource [' . $resource . '] is not mapped to any Model.');
        }

        $allowedActions = ['index', 'store', 'show', 'update', 'destroy'];

        if (!in_array($action, $allowedActions)) {
            throw new InvalidArgumentException('[' . $action . '] is not a valid action.');
        }

        // If we have a $relation parameter, then we generate a command based on it
        if ($relation) {
            if (!isset($mapping[$relation])) {
                throw new NotFoundHttpException('The resource [' . $resource . '] is not mapped to any Model.');
            }

            $command = implode('\\', [
                $namespace,
                'Commands',
                $mapping[$resource] . 'Command',
                ucfirst($mapping[$relation]) . ucfirst($action) . 'Command'
            ]);
        } else {
            $command = implode('\\', [
                $namespace,
                'Commands',
                $mapping[$resource] . 'Command',
                ucfirst($action) . 'Command'
            ]);
        }

        // If no custom command is found, then we use one of the default ones
        if (!class_exists($command)) {
            if ($relation) {
                $command = implode('\\', [
                    'Osedea',
                    'LaravelRest',
                    'Commands',
                    'DefaultCommand',
                    'Relation' . ucfirst($action) . 'Command'
                ]);
            } else {
                $command = implode('\\', [
                    'Osedea',
                    'LaravelRest',
                    'Commands',
                    'DefaultCommand',
                    ucfirst($action) . 'Command'
                ]);
            }
        }

        if (!class_exists($command)) {
            throw new NotFoundHttpException('There is no default command for this action and resource.');
        }

        return $command;
    }

Returns a command class name based on a resource mapping.

Examples:
- getCommandFromResource('users', 'show') returns \App\Commands\UserCommand\ShowCommand
- getCommandFromResource('users', 'index', 'groups') returns \App\Commands\UserCommand\GroupIndexCommand

@param string $resource
@param string $action
@param string|null $relation
@return string
@throws NotFoundHttpException

Returns a command class name based on a resource mapping .


protected function runBeforeCommands($command)
    {
        $beforeCommands = $command::beforeCommands();

        if (!is_array($beforeCommands) && strlen(trim($beforeCommands)) > 0) {
            $beforeCommands = [$beforeCommands];
        }

        $this->dispatcher->pipeThrough($beforeCommands);
    }

protected function runBeforeCommands ( $ command ) { $ beforeCommands = $ command :: beforeCommands ( ) ; if ( ! is_array ( $ beforeCommands ) && strlen ( trim ( $ beforeCommands ) ) > 0 ) { $ beforeCommands = [ $ beforeCommands ] ; } $ this -> dispatcher -> pipeThrough ( $ beforeCommands ) ; }

This method can be used in a controller before dispatching a command to pipe it.
It will check if the command has commands to run in the command pipeline.

@param string $command A command class name

This method can be used in a controller before dispatching a command to pipe it . It will check if the command has commands to run in the command pipeline .


protected function getPerPageFromModelClass($modelClass) {
        // We need this empty model to grab perPage and perPageMax parameters
        $model = new $modelClass;

        // If Model::$perPage equals 0, then pagination is disabled
        if ($model->getPerPage() == 0) {
            return $modelClass::all();
        }

        // The number of items per page can be overriden as a query parameter
        $perPage = Request::input('perPage', $model->getPerPage());

        // We make sure the $perPage parameter is not higher than the maximum for this model
        if ($perPage > $model->getPerPageMax()) {
            $perPage = $model->getPerPageMax();
        }

        return $perPage;
    }

Returns an integer for pagination based on a model's class.

@param  string $modelClass A model's class.
@return int The number of items per page for the given model.

Returns an integer for pagination based on a model s class .


protected function addWhereStatements($query, $class)
    {
        $params = Request::all();

        foreach ($params as $key => $value) {
            if (!in_array($key, $this->keywordParams) && !in_array($key, $class::$filterable)) {
                throw new InvalidFilterException;
            }

            if (!in_array($key, $this->keywordParams)) {
                $query->where($key, '=', $value);
            }
        }

        return $query;
    }

protected function addWhereStatements ( $ query , $ class ) { $ params = Request :: all ( ) ; foreach ( $ params as $ key => $ value ) { if ( ! in_array ( $ key , $ this -> keywordParams ) && ! in_array ( $ key , $ class :: $ filterable ) ) { throw new InvalidFilterException ; } if ( ! in_array ( $ key , $ this -> keywordParams ) ) { $ query -> where ( $ key , '=' , $ value ) ; } } return $ query ; }

Loop through Request params, creating `where` statements.

@param $query
@return mixed

Loop through Request params creating where statements .


public function boot()
    {
        $this->publishes([
            implode(DIRECTORY_SEPARATOR, [__DIR__, 'config', 'api.php']) => config_path('api.php')
        ]);

        $this->setupRoutes($this->app->router);
    }

public function boot ( ) { $ this -> publishes ( [ implode ( DIRECTORY_SEPARATOR , [ __DIR__ , 'config' , 'api.php' ] ) => config_path ( 'api.php' ) ] ) ; $ this -> setupRoutes ( $ this -> app -> router ) ; }


public function allow($methods = [])
    {
        $methods = $methods ? (array) $methods : [];
        $methods = array_map('strtoupper', $methods);
        $this->_methods = array_fill_keys($methods, true) + $this->_methods;
        return $this;
    }

public function allow ( $ methods = [ ] ) { $ methods = $ methods ? ( array ) $ methods : [ ] ; $ methods = array_map ( 'strtoupper' , $ methods ) ; $ this -> _methods = array_fill_keys ( $ methods , true ) + $ this -> _methods ; return $ this ; }

Allows additionnal methods.

@param  string|array $methods The methods to allow.
@return self


public function pattern($pattern = null)
    {
        if (!func_num_args()) {
            return $this->_pattern;
        }
        $this->_token = null;
        $this->_regex = null;
        $this->_variables = null;

        if (!$pattern || $pattern[0] !== '[') {
            $pattern = '/' . trim($pattern, '/');
        }

        $this->_pattern = $this->_prefix . $pattern;
        return $this;
    }

public function pattern ( $ pattern = null ) { if ( ! func_num_args ( ) ) { return $ this -> _pattern ; } $ this -> _token = null ; $ this -> _regex = null ; $ this -> _variables = null ; if ( ! $ pattern || $ pattern [ 0 ] !== '[' ) { $ pattern = '/' . trim ( $ pattern , '/' ) ; } $ this -> _pattern = $ this -> _prefix . $ pattern ; return $ this ; }

Gets the route's pattern.

@return array The route's pattern.


public function token()
    {
        if ($this->_token === null) {
            $parser = $this->_classes['parser'];
            $this->_token = [];
            $this->_regex = null;
            $this->_variables = null;
            $this->_token = $parser::tokenize($this->_pattern, '/');
        }
        return $this->_token;
    }

public function token ( ) { if ( $ this -> _token === null ) { $ parser = $ this -> _classes [ 'parser' ] ; $ this -> _token = [ ] ; $ this -> _regex = null ; $ this -> _variables = null ; $ this -> _token = $ parser :: tokenize ( $ this -> _pattern , '/' ) ; } return $ this -> _token ; }

Returns the route's token structures.

@return array A collection route's token structure.


public function regex()
    {
        if ($this->_regex !== null) {
            return $this->_regex;
        }
        $this->_compile();
        return $this->_regex;
    }

public function regex ( ) { if ( $ this -> _regex !== null ) { return $ this -> _regex ; } $ this -> _compile ( ) ; return $ this -> _regex ; }

Gets the route's regular expression pattern.

@return string the route's regular expression pattern.

Gets the route s regular expression pattern .


public function variables()
    {
        if ($this->_variables !== null) {
            return $this->_variables;
        }
        $this->_compile();
        return $this->_variables;
    }

public function variables ( ) { if ( $ this -> _variables !== null ) { return $ this -> _variables ; } $ this -> _compile ( ) ; return $ this -> _variables ; }

Gets the route's variables and their associated pattern in case of array variables.

@return array The route's variables and their associated pattern.

Gets the route s variables and their associated pattern in case of array variables .


public function match($request, &$variables = null, &$hostVariables = null)
    {
        $hostVariables = [];

        if (($host = $this->host()) && !$host->match($request, $hostVariables)) {
            return false;
        }

        $path = isset($request['path']) ? $request['path'] : '';
        $method = isset($request['method']) ? $request['method'] : '*';

        if (!isset($this->_methods['*']) && $method !== '*' && !isset($this->_methods[$method])) {
            if ($method !== 'HEAD' && !isset($this->_methods['GET'])) {
                return false;
            }
        }

        $path = '/' . trim($path, '/');

        if (!preg_match('~^' . $this->regex() . '$~', $path, $matches)) {
            return false;
        }
        $variables = $this->_buildVariables($matches);
        $this->params = $hostVariables + $variables;
        return true;
    }

public function match ( $ request , & $ variables = null , & $ hostVariables = null ) { $ hostVariables = [ ] ; if ( ( $ host = $ this -> host ( ) ) && ! $ host -> match ( $ request , $ hostVariables ) ) { return false ; } $ path = isset ( $ request [ 'path' ] ) ? $ request [ 'path' ] : '' ; $ method = isset ( $ request [ 'method' ] ) ? $ request [ 'method' ] : '*' ; if ( ! isset ( $ this -> _methods [ '*' ] ) && $ method !== '*' && ! isset ( $ this -> _methods [ $ method ] ) ) { if ( $ method !== 'HEAD' && ! isset ( $ this -> _methods [ 'GET' ] ) ) { return false ; } } $ path = '/' . trim ( $ path , '/' ) ; if ( ! preg_match ( '~^' . $ this -> regex ( ) . '$~' , $ path , $ matches ) ) { return false ; } $ variables = $ this -> _buildVariables ( $ matches ) ; $ this -> params = $ hostVariables + $ variables ; return true ; }

Checks if the route instance matches a request.

@param  array   $request a request.
@return boolean

Checks if the route instance matches a request .


protected function _buildVariables($values)
    {
        $variables = [];
        $parser = $this->_classes['parser'];

        $i = 1;
        foreach ($this->variables() as $name => $pattern) {
            if (!isset($values[$i])) {
                $variables[$name] = !$pattern ? null : [];
                continue;
            }
            if (!$pattern) {
                $variables[$name] = $values[$i] ?: null;
            } else {
                $token = $parser::tokenize($pattern, '/');
                $rule = $parser::compile($token);
                if (preg_match_all('~' . $rule[0] . '~', $values[$i], $parts)) {
                    foreach ($parts[1] as $value) {
                        if (strpos($value, '/') !== false) {
                            $variables[$name][] = explode('/', $value);
                        } else {
                            $variables[$name][] = $value;
                        }
                    }
                } else {
                    $variables[$name] = [];
                }
            }
            $i++;
        }
        return $variables;
    }

protected function _buildVariables ( $ values ) { $ variables = [ ] ; $ parser = $ this -> _classes [ 'parser' ] ; $ i = 1 ; foreach ( $ this -> variables ( ) as $ name => $ pattern ) { if ( ! isset ( $ values [ $ i ] ) ) { $ variables [ $ name ] = ! $ pattern ? null : [ ] ; continue ; } if ( ! $ pattern ) { $ variables [ $ name ] = $ values [ $ i ] ? : null ; } else { $ token = $ parser :: tokenize ( $ pattern , '/' ) ; $ rule = $ parser :: compile ( $ token ) ; if ( preg_match_all ( '~' . $ rule [ 0 ] . '~' , $ values [ $ i ] , $ parts ) ) { foreach ( $ parts [ 1 ] as $ value ) { if ( strpos ( $ value , '/' ) !== false ) { $ variables [ $ name ] [ ] = explode ( '/' , $ value ) ; } else { $ variables [ $ name ] [ ] = $ value ; } } } else { $ variables [ $ name ] = [ ] ; } } $ i ++ ; } return $ variables ; }

Combines route's variables names with the regex matched route's values.

@param  array $varNames The variable names array with their corresponding pattern segment when applicable.
@param  array $values   The matched values.
@return array           The route's variables.

Combines route s variables names with the regex matched route s values .


public function dispatch($response = null)
    {
        if ($error = $this->error()) {
            throw new RouterException($this->message(), $error);
        }
        $this->response = $response;
        $request = $this->request;

        $generator = $this->middleware();

        $next = function() use ($request, $response, $generator, &$next) {
            $handler = $generator->current();
            $generator->next();
            return $handler($request, $response, $next);
        };
        return $next();
    }

public function dispatch ( $ response = null ) { if ( $ error = $ this -> error ( ) ) { throw new RouterException ( $ this -> message ( ) , $ error ) ; } $ this -> response = $ response ; $ request = $ this -> request ; $ generator = $ this -> middleware ( ) ; $ next = function ( ) use ( $ request , $ response , $ generator , & $ next ) { $ handler = $ generator -> current ( ) ; $ generator -> next ( ) ; return $ handler ( $ request , $ response , $ next ) ; } ; return $ next ( ) ; }

Dispatches the route.

@param  mixed $response The outgoing response.
@return mixed           The handler return value.


public function link($params = [], $options = [])
    {
        $defaults = [
            'absolute' => false,
            'basePath' => '',
            'query'    => '',
            'fragment' => ''
        ];

        $options = array_filter($options, function($value) { return $value !== '*'; });
        $options += $defaults;

        $params = $params + $this->params;

        $link = $this->_link($this->token(), $params);

        $basePath = trim($options['basePath'], '/');
        if ($basePath) {
            $basePath = '/' . $basePath;
        }
        $link = isset($link) ? ltrim($link, '/') : '';
        $link = $basePath . ($link ? '/' . $link : $link);
        $query = $options['query'] ? '?' . $options['query'] : '';
        $fragment = $options['fragment'] ? '#' . $options['fragment'] : '';

        if ($options['absolute']) {
            if ($host = $this->host()) {
                $link = $host->link($params, $options) . "{$link}";
            } else {
                $scheme = !empty($options['scheme']) ? $options['scheme'] . '://' : '//';
                $host = isset($options['host']) ? $options['host'] : 'localhost';
                $link = "{$scheme}{$host}{$link}";
            }
        }

        return $link . $query . $fragment;
    }

public function link ( $ params = [ ] , $ options = [ ] ) { $ defaults = [ 'absolute' => false , 'basePath' => '' , 'query' => '' , 'fragment' => '' ] ; $ options = array_filter ( $ options , function ( $ value ) { return $ value !== '*' ; } ) ; $ options += $ defaults ; $ params = $ params + $ this -> params ; $ link = $ this -> _link ( $ this -> token ( ) , $ params ) ; $ basePath = trim ( $ options [ 'basePath' ] , '/' ) ; if ( $ basePath ) { $ basePath = '/' . $ basePath ; } $ link = isset ( $ link ) ? ltrim ( $ link , '/' ) : '' ; $ link = $ basePath . ( $ link ? '/' . $ link : $ link ) ; $ query = $ options [ 'query' ] ? '?' . $ options [ 'query' ] : '' ; $ fragment = $ options [ 'fragment' ] ? '#' . $ options [ 'fragment' ] : '' ; if ( $ options [ 'absolute' ] ) { if ( $ host = $ this -> host ( ) ) { $ link = $ host -> link ( $ params , $ options ) . "{$link}" ; } else { $ scheme = ! empty ( $ options [ 'scheme' ] ) ? $ options [ 'scheme' ] . '://' : '//' ; $ host = isset ( $ options [ 'host' ] ) ? $ options [ 'host' ] : 'localhost' ; $ link = "{$scheme}{$host}{$link}" ; } } return $ link . $ query . $ fragment ; }

Returns the route's link.

@param  array  $params  The route parameters.
@param  array  $options Options for generating the proper prefix. Accepted values are:
- `'absolute'` _boolean_: `true` or `false`.
- `'scheme'`   _string_ : The scheme.
- `'host'`     _string_ : The host name.
- `'basePath'` _string_ : The base path.
- `'query'`    _string_ : The query string.
- `'fragment'` _string_ : The fragment string.
@return string          The link.


protected function _compile()
    {
        if ($this->pattern() === '*') {
            return;
        }
        $parser = $this->_classes['parser'];
        $rule = $parser::compile($this->token());
        $this->_regex = $rule[0];
        $this->_variables = $rule[1];
    }

protected function _compile ( ) { if ( $ this -> pattern ( ) === '*' ) { return ; } $ parser = $ this -> _classes [ 'parser' ] ; $ rule = $ parser :: compile ( $ this -> token ( ) ) ; $ this -> _regex = $ rule [ 0 ] ; $ this -> _variables = $ rule [ 1 ] ; }


public function match($request, &$hostVariables = null)
    {
        $defaults = [
            'host'   => '*',
            'scheme' => '*'
        ];
        $request += $defaults;
        $scheme = $request['scheme'];
        $host = $request['host'];

        $hostVariables = [];

        $anyHost = $this->pattern() === '*' || $host === '*';
        $anyScheme = $this->scheme() === '*' || $scheme === '*';

        if ($anyHost) {
            if ($this->variables()) {
                $hostVariables = array_fill_keys(array_keys($this->variables()), null);
            }
            return $anyScheme || $this->scheme() === $scheme;
        }

        if (!$anyScheme && $this->scheme() !== $scheme) {
            return false;
        }

        if (!preg_match('~^' . $this->regex() . '$~', $host, $matches)) {
            $hostVariables = null;
            return false;
        }
        $i = 0;

        foreach ($this->variables() as $name => $pattern) {
            $hostVariables[$name] = $matches[++$i];
        }
        return true;
    }

public function match ( $ request , & $ hostVariables = null ) { $ defaults = [ 'host' => '*' , 'scheme' => '*' ] ; $ request += $ defaults ; $ scheme = $ request [ 'scheme' ] ; $ host = $ request [ 'host' ] ; $ hostVariables = [ ] ; $ anyHost = $ this -> pattern ( ) === '*' || $ host === '*' ; $ anyScheme = $ this -> scheme ( ) === '*' || $ scheme === '*' ; if ( $ anyHost ) { if ( $ this -> variables ( ) ) { $ hostVariables = array_fill_keys ( array_keys ( $ this -> variables ( ) ) , null ) ; } return $ anyScheme || $ this -> scheme ( ) === $ scheme ; } if ( ! $ anyScheme && $ this -> scheme ( ) !== $ scheme ) { return false ; } if ( ! preg_match ( '~^' . $ this -> regex ( ) . '$~' , $ host , $ matches ) ) { $ hostVariables = null ; return false ; } $ i = 0 ; foreach ( $ this -> variables ( ) as $ name => $ pattern ) { $ hostVariables [ $ name ] = $ matches [ ++ $ i ] ; } return true ; }

Checks if a host matches a host pattern.

@param  string  $host          The host to check.
@param  string  $hostVariables The matches host variables
@return boolean                Returns `true` on success, false otherwise.

Checks if a host matches a host pattern .


public function link($params = [], $options = [])
    {
        $defaults = [
            'scheme'   => $this->scheme()
        ];
        $options += $defaults;

        if (!isset($options['host'])) {
            $options['host'] = $this->_link($this->token(), $params);
        }

        $scheme = $options['scheme'] !== '*' ? $options['scheme'] . '://' : '//';
        return $scheme . $options['host'];
    }

public function link ( $ params = [ ] , $ options = [ ] ) { $ defaults = [ 'scheme' => $ this -> scheme ( ) ] ; $ options += $ defaults ; if ( ! isset ( $ options [ 'host' ] ) ) { $ options [ 'host' ] = $ this -> _link ( $ this -> token ( ) , $ params ) ; } $ scheme = $ options [ 'scheme' ] !== '*' ? $ options [ 'scheme' ] . '://' : '//' ; return $ scheme . $ options [ 'host' ] ; }

Returns the host's link.

@param  array  $params  The host parameters.
@param  array  $options Options for generating the proper prefix. Accepted values are:
- `'scheme'`   _string_ : The scheme.
- `'host'`     _string_ : The host name.
@return string          The link.


public static function tokenize($pattern, $delimiter = '/')
    {
        // Checks if the pattern has some optional segments.
        if (count(preg_split('~' . static::PLACEHOLDER_REGEX . '(*SKIP)(*F)|\[~x', $pattern)) > 1) {
            $tokens = static::_tokenizePattern($pattern, $delimiter);
        } else {
            $tokens = static::_tokenizeSegment($pattern, $delimiter);
        }
        return [
            'optional' => false,
            'greedy'   => '',
            'repeat'   => false,
            'pattern'  => $pattern,
            'tokens'   => $tokens
        ];
    }

Tokenizes a route pattern. Optional segments are identified by square brackets.

@param string $pattern   A route pattern
@param string $delimiter The path delimiter.
@param array             The tokens structure root node.

Tokenizes a route pattern . Optional segments are identified by square brackets .


protected static function _tokenizePattern($pattern, $delimiter, &$variable = null)
    {
        $tokens = [];
        $index = 0;
        $path = '';
        $parts = static::split($pattern);

        foreach ($parts as $part) {
            if (is_string($part)) {
                $tokens = array_merge($tokens, static::_tokenizeSegment($part, $delimiter, $variable));
                continue;
            }

            $greedy = $part[1];
            $repeat = $greedy === '+' || $greedy === '*';
            $optional = $greedy === '?' || $greedy === '*';

            $children = static::_tokenizePattern($part[0], $delimiter, $variable);

            $tokens[] = [
                'optional' => $optional,
                'greedy'   => $greedy ?: '?',
                'repeat'   => $repeat ? $variable : false,
                'pattern'  => $part[0],
                'tokens'   => $children
            ];

        }
        return $tokens;
    }

protected static function _tokenizePattern ( $ pattern , $ delimiter , & $ variable = null ) { $ tokens = [ ] ; $ index = 0 ; $ path = '' ; $ parts = static :: split ( $ pattern ) ; foreach ( $ parts as $ part ) { if ( is_string ( $ part ) ) { $ tokens = array_merge ( $ tokens , static :: _tokenizeSegment ( $ part , $ delimiter , $ variable ) ) ; continue ; } $ greedy = $ part [ 1 ] ; $ repeat = $ greedy === '+' || $ greedy === '*' ; $ optional = $ greedy === '?' || $ greedy === '*' ; $ children = static :: _tokenizePattern ( $ part [ 0 ] , $ delimiter , $ variable ) ; $ tokens [ ] = [ 'optional' => $ optional , 'greedy' => $ greedy ? : '?' , 'repeat' => $ repeat ? $ variable : false , 'pattern' => $ part [ 0 ] , 'tokens' => $ children ] ; } return $ tokens ; }

Tokenizes patterns.

@param string $pattern   A route pattern
@param string $delimiter The path delimiter.
@param array             An array of tokens structure.


protected static function _tokenizeSegment($pattern, $delimiter, &$variable = null)
    {
        $tokens = [];
        $index = 0;
        $path = '';

        if (preg_match_all('~' . static::PLACEHOLDER_REGEX . '()~x', $pattern, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER)) {
            foreach ($matches as $match) {
                $offset = $match[0][1];

                $path .= substr($pattern, $index, $offset - $index);
                $index = $offset + strlen($match[0][0]);

                if ($path) {
                    $tokens[] = $path;
                    $path = '';
                }

                $variable = $match[1][0];
                $capture = $match[2][0] ?: '[^' . $delimiter . ']+';

                $tokens[] = [
                    'name'      => $variable,
                    'pattern'   => $capture
                ];
            }
        }

        if ($index < strlen($pattern)) {
            $path .= substr($pattern, $index);
            if ($path) {
                $tokens[] = $path;
            }
        }
        return $tokens;
    }

protected static function _tokenizeSegment ( $ pattern , $ delimiter , & $ variable = null ) { $ tokens = [ ] ; $ index = 0 ; $ path = '' ; if ( preg_match_all ( '~' . static :: PLACEHOLDER_REGEX . '()~x' , $ pattern , $ matches , PREG_OFFSET_CAPTURE | PREG_SET_ORDER ) ) { foreach ( $ matches as $ match ) { $ offset = $ match [ 0 ] [ 1 ] ; $ path .= substr ( $ pattern , $ index , $ offset - $ index ) ; $ index = $ offset + strlen ( $ match [ 0 ] [ 0 ] ) ; if ( $ path ) { $ tokens [ ] = $ path ; $ path = '' ; } $ variable = $ match [ 1 ] [ 0 ] ; $ capture = $ match [ 2 ] [ 0 ] ? : '[^' . $ delimiter . ']+' ; $ tokens [ ] = [ 'name' => $ variable , 'pattern' => $ capture ] ; } } if ( $ index < strlen ( $ pattern ) ) { $ path .= substr ( $ pattern , $ index ) ; if ( $ path ) { $ tokens [ ] = $ path ; } } return $ tokens ; }

Tokenizes segments which are patterns with optional segments filtered out.
Only classic placeholder are supported.

@param string $pattern   A route pattern with no optional segments.
@param string $delimiter The path delimiter.
@param array             An array of tokens structure.

Tokenizes segments which are patterns with optional segments filtered out . Only classic placeholder are supported .


public static function split($pattern)
    {
        $segments = [];
        $len = strlen($pattern);
        $buffer = '';
        $opened = 0;
        for ($i = 0; $i < $len; $i++) {
            if ($pattern[$i] === '{') {
                do {
                    $buffer .= $pattern[$i++];
                    if ($pattern[$i] === '}') {
                        $buffer .= $pattern[$i];
                        break;
                    }
                } while ($i < $len);
            } elseif ($pattern[$i] === '[') {
                $opened++;
                if ($opened === 1) {
                    $segments[] = $buffer;
                    $buffer = '';
                } else {
                    $buffer .= $pattern[$i];
                }
            } elseif ($pattern[$i] === ']') {
                $opened--;
                if ($opened === 0) {
                    $greedy = '?';
                    if ($i < $len -1) {
                        if ($pattern[$i + 1] === '*' || $pattern[$i + 1] === '+') {
                            $greedy = $pattern[$i + 1];
                            $i++;
                        }
                    }
                    $segments[] = [$buffer, $greedy];
                    $buffer = '';
                } else {
                    $buffer .= $pattern[$i];
                }
            } else {
                $buffer .= $pattern[$i];
            }
        }
        if ($buffer) {
            $segments[] = $buffer;
        }
        if ($opened) {
            throw ParserException::squareBracketMismatch();
        }
        return $segments;
    }

public static function split ( $ pattern ) { $ segments = [ ] ; $ len = strlen ( $ pattern ) ; $ buffer = '' ; $ opened = 0 ; for ( $ i = 0 ; $ i < $ len ; $ i ++ ) { if ( $ pattern [ $ i ] === '{' ) { do { $ buffer .= $ pattern [ $ i ++ ] ; if ( $ pattern [ $ i ] === '}' ) { $ buffer .= $ pattern [ $ i ] ; break ; } } while ( $ i < $ len ) ; } elseif ( $ pattern [ $ i ] === '[' ) { $ opened ++ ; if ( $ opened === 1 ) { $ segments [ ] = $ buffer ; $ buffer = '' ; } else { $ buffer .= $ pattern [ $ i ] ; } } elseif ( $ pattern [ $ i ] === ']' ) { $ opened -- ; if ( $ opened === 0 ) { $ greedy = '?' ; if ( $ i < $ len - 1 ) { if ( $ pattern [ $ i + 1 ] === '*' || $ pattern [ $ i + 1 ] === '+' ) { $ greedy = $ pattern [ $ i + 1 ] ; $ i ++ ; } } $ segments [ ] = [ $ buffer , $ greedy ] ; $ buffer = '' ; } else { $ buffer .= $ pattern [ $ i ] ; } } else { $ buffer .= $ pattern [ $ i ] ; } } if ( $ buffer ) { $ segments [ ] = $ buffer ; } if ( $ opened ) { throw ParserException :: squareBracketMismatch ( ) ; } return $ segments ; }

Splits a pattern in segments and patterns.
segments will be represented by string value and patterns by an array containing
the string pattern as first value and the greedy value as second value.

example:
`/user[/{id}]*` will gives `['/user', ['id', '*']]`

Unfortunately recursive regex matcher can't help here so this function is required.

@param string $pattern A route pattern.
@param array           The splitted pattern.

Splits a pattern in segments and patterns . segments will be represented by string value and patterns by an array containing the string pattern as first value and the greedy value as second value .


public static function compile($token)
    {
        $variables = [];
        $regex = '';
        foreach ($token['tokens'] as $child) {
            if (is_string($child)) {
                $regex .= preg_quote($child, '~');
            } elseif (isset($child['tokens'])) {
                $rule = static::compile($child);
                if ($child['repeat']) {
                    if (count($rule[1]) > 1) {
                        throw ParserException::placeholderExceeded();
                    }
                    $regex .= '((?:' . $rule[0] . ')' . $child['greedy'] . ')';
                } elseif ($child['optional']) {
                    $regex .= '(?:' . $rule[0] . ')?';
                }
                foreach ($rule[1] as $name => $pattern) {
                    if (isset($variables[$name])) {
                        throw ParserException::duplicatePlaceholder($name);
                    }
                    $variables[$name] = $pattern;
                }
            } else {
                $name = $child['name'];
                if (isset($variables[$name])) {
                    throw ParserException::duplicatePlaceholder($name);
                }
                if ($token['repeat']) {
                    $variables[$name] = $token['pattern'];
                    $regex .= $child['pattern'];
                } else {
                    $variables[$name] = false;
                    $regex .= '(' . $child['pattern'] . ')';
                }
            }
        }
        return [$regex, $variables];
    }

public static function compile ( $ token ) { $ variables = [ ] ; $ regex = '' ; foreach ( $ token [ 'tokens' ] as $ child ) { if ( is_string ( $ child ) ) { $ regex .= preg_quote ( $ child , '~' ) ; } elseif ( isset ( $ child [ 'tokens' ] ) ) { $ rule = static :: compile ( $ child ) ; if ( $ child [ 'repeat' ] ) { if ( count ( $ rule [ 1 ] ) > 1 ) { throw ParserException :: placeholderExceeded ( ) ; } $ regex .= '((?:' . $ rule [ 0 ] . ')' . $ child [ 'greedy' ] . ')' ; } elseif ( $ child [ 'optional' ] ) { $ regex .= '(?:' . $ rule [ 0 ] . ')?' ; } foreach ( $ rule [ 1 ] as $ name => $ pattern ) { if ( isset ( $ variables [ $ name ] ) ) { throw ParserException :: duplicatePlaceholder ( $ name ) ; } $ variables [ $ name ] = $ pattern ; } } else { $ name = $ child [ 'name' ] ; if ( isset ( $ variables [ $ name ] ) ) { throw ParserException :: duplicatePlaceholder ( $ name ) ; } if ( $ token [ 'repeat' ] ) { $ variables [ $ name ] = $ token [ 'pattern' ] ; $ regex .= $ child [ 'pattern' ] ; } else { $ variables [ $ name ] = false ; $ regex .= '(' . $ child [ 'pattern' ] . ')' ; } } } return [ $ regex , $ variables ] ; }

Builds a regex from a tokens structure array.

@param  array $token A tokens structure root node.
@return array        An array containing the regex pattern and its associated variable names.

Builds a regex from a tokens structure array .


public function scopify($options)
    {
        $scope = $this->_scope;

        if (!empty($options['name'])) {
            $options['name'] = $scope['name'] ? $scope['name'] . '.' . $options['name'] : $options['name'];
        }

        if (!empty($options['prefix'])) {
            $options['prefix'] = $scope['prefix'] . trim($options['prefix'], '/');
            $options['prefix'] = $options['prefix'] ? $options['prefix'] . '/' : '';
        }

        if (isset($options['persist'])) {
            $options['persist'] = ((array) $options['persist']) + $scope['persist'];
        }

        if (isset($options['namespace'])) {
            $options['namespace'] = $scope['namespace'] . trim($options['namespace'], '\\') . '\\';
        }

        return $options + $scope;
    }

public function scopify ( $ options ) { $ scope = $ this -> _scope ; if ( ! empty ( $ options [ 'name' ] ) ) { $ options [ 'name' ] = $ scope [ 'name' ] ? $ scope [ 'name' ] . '.' . $ options [ 'name' ] : $ options [ 'name' ] ; } if ( ! empty ( $ options [ 'prefix' ] ) ) { $ options [ 'prefix' ] = $ scope [ 'prefix' ] . trim ( $ options [ 'prefix' ] , '/' ) ; $ options [ 'prefix' ] = $ options [ 'prefix' ] ? $ options [ 'prefix' ] . '/' : '' ; } if ( isset ( $ options [ 'persist' ] ) ) { $ options [ 'persist' ] = ( ( array ) $ options [ 'persist' ] ) + $ scope [ 'persist' ] ; } if ( isset ( $ options [ 'namespace' ] ) ) { $ options [ 'namespace' ] = $ scope [ 'namespace' ] . trim ( $ options [ 'namespace' ] , '\\' ) . '\\' ; } return $ options + $ scope ; }

Scopes an options array according to the instance scope data.

@param  array $options The options to scope.
@return array          The scoped options.

Scopes an options array according to the instance scope data .


public function bind($pattern, $options = [], $handler = null)
    {
        if (!is_array($options)) {
            $handler = $options;
            $options = [];
        }
        if (!$handler instanceof Closure && !method_exists($handler, '__invoke')) {
            throw new RouterException("The handler needs to be an instance of `Closure` or implements the `__invoke()` magic method.");
        }

        if (isset($options['method'])) {
            throw new RouterException("Use the `'methods'` option to limit HTTP verbs on a route binding definition.");
        }

        $scope = end($this->_scopes);
        $options = $scope->scopify($options);
        $options['pattern'] = $pattern;
        $options['handler'] = $handler;
        $options['scope'] = $scope;

        $scheme = $options['scheme'];
        $host = $options['host'];

        if (isset($this->_hosts[$scheme][$host])) {
            $options['host'] = $this->_hosts[$scheme][$host];
        }

        if (isset($this->_pattern[$scheme][$host][$pattern])) {
            $instance = $this->_pattern[$scheme][$host][$pattern];
        } else {
            $route = $this->_classes['route'];
            $instance = new $route($options);
            $this->_hosts[$scheme][$host] = $instance->host();
        }

        if (!isset($this->_pattern[$scheme][$host][$pattern])) {
            $this->_pattern[$scheme][$host][$pattern] = $instance;
        }

        $methods = $options['methods'] ? (array) $options['methods'] : [];

        $instance->allow($methods);

        foreach ($methods as $method) {
            $this->_routes[$scheme][$host][strtoupper($method)][] = $instance;
        }

        if (isset($options['name'])) {
            $this->_data[$options['name']] = $instance;
        }
        return $instance;
    }

Adds a route.

@param  string|array  $pattern The route's pattern.
@param  Closure|array $options An array of options or the callback handler.
@param  Closure|null  $handler The callback handler.
@return self


public function group($prefix, $options, $handler = null)
    {
        if (!is_array($options)) {
            $handler = $options;
            if (is_string($prefix)) {
                $options = [];
            } else {
                $options = $prefix;
                $prefix = '';
            }
        }
        if (!$handler instanceof Closure && !method_exists($handler, '__invoke')) {
            throw new RouterException("The handler needs to be an instance of `Closure` or implements the `__invoke()` magic method.");
        }

        $options['prefix'] = isset($options['prefix']) ? $options['prefix'] : $prefix;

        $scope = $this->scope();

        $this->pushScope($scope->seed($options));

        $handler($this);

        return $this->popScope();
    }

Groups some routes inside a new scope.

@param  string|array  $prefix  The group's prefix pattern or the options array.
@param  Closure|array $options An array of options or the callback handler.
@param  Closure|null  $handler The callback handler.
@return object                 The newly created scope instance.


public function route($request)
    {
        $defaults = [
            'path'   => '',
            'method' => 'GET',
            'host'   => '*',
            'scheme' => '*'
        ];

        $this->_defaults = [];

        if ($request instanceof RequestInterface) {
            $uri = $request->getUri();
            $r = [
                'scheme' => $uri->getScheme(),
                'host'   => $uri->getHost(),
                'method' => $request->getMethod(),
                'path'   => $uri->getPath()
            ];
            if (method_exists($request, 'basePath')) {
                $this->basePath($request->basePath());
            }
        } elseif (!is_array($request)) {
            $r = array_combine(array_keys($defaults), func_get_args() + array_values($defaults));
        } else {
            $r = $request + $defaults;
        }
        $r = $this->_normalizeRequest($r);

        if ($route = $this->_route($r)) {
            $route->request = is_object($request) ? $request : $r;
            foreach ($route->persist as $key) {
                if (isset($route->params[$key])) {
                    $this->_defaults[$key] = $route->params[$key];
                }
            }
        } else {
            $route = $this->_classes['route'];
            $error = $route::NOT_FOUND;
            $message = "No route found for `{$r['scheme']}:{$r['host']}:{$r['method']}:/{$r['path']}`.";
            $route = new $route(compact('error', 'message'));
        }

        return $route;
    }

Routes a Request.

@param  mixed  $request The request to route.
@return object          A route matching the request or a "route not found" route.


protected function _normalizeRequest($request)
    {
        if (preg_match('~^(?:[a-z]+:)?//~i', $request['path'])) {
            $parsed = array_intersect_key(parse_url($request['path']), $request);
            $request = $parsed + $request;
        }
        $request['path'] = (ltrim(strtok($request['path'], '?'), '/'));
        $request['method'] = strtoupper($request['method']);
        return $request;
    }

protected function _normalizeRequest ( $ request ) { if ( preg_match ( '~^(?:[a-z]+:)?//~i' , $ request [ 'path' ] ) ) { $ parsed = array_intersect_key ( parse_url ( $ request [ 'path' ] ) , $ request ) ; $ request = $ parsed + $ request ; } $ request [ 'path' ] = ( ltrim ( strtok ( $ request [ 'path' ] , '?' ) , '/' ) ) ; $ request [ 'method' ] = strtoupper ( $ request [ 'method' ] ) ; return $ request ; }

Normalizes a request.

@param  array $request The request to normalize.
@return array          The normalized request.


protected function _route($request)
    {
        $path = $request['path'];
        $httpMethod = $request['method'];
        $host = $request['host'];
        $scheme = $request['scheme'];

        $allowedSchemes = array_unique([$scheme => $scheme, '*' => '*']);
        $allowedMethods = array_unique([$httpMethod => $httpMethod, '*' => '*']);

        if ($httpMethod === 'HEAD') {
            $allowedMethods += ['GET' => 'GET'];
        }

        foreach ($this->_routes as $scheme => $hostBasedRoutes) {
            if (!isset($allowedSchemes[$scheme])) {
                continue;
            }
            foreach ($hostBasedRoutes as $routeHost => $methodBasedRoutes) {
                foreach ($methodBasedRoutes as $method => $routes) {
                    if (!isset($allowedMethods[$method]) && $httpMethod !== '*') {
                        continue;
                    }
                    foreach ($routes as $route) {
                        if (!$route->match($request, $variables, $hostVariables)) {
                            if ($hostVariables === null) {
                                continue 3;
                            }
                            continue;
                        }
                        return $route;
                    }
                }
            }
        }
    }

protected function _route ( $ request ) { $ path = $ request [ 'path' ] ; $ httpMethod = $ request [ 'method' ] ; $ host = $ request [ 'host' ] ; $ scheme = $ request [ 'scheme' ] ; $ allowedSchemes = array_unique ( [ $ scheme => $ scheme , '*' => '*' ] ) ; $ allowedMethods = array_unique ( [ $ httpMethod => $ httpMethod , '*' => '*' ] ) ; if ( $ httpMethod === 'HEAD' ) { $ allowedMethods += [ 'GET' => 'GET' ] ; } foreach ( $ this -> _routes as $ scheme => $ hostBasedRoutes ) { if ( ! isset ( $ allowedSchemes [ $ scheme ] ) ) { continue ; } foreach ( $ hostBasedRoutes as $ routeHost => $ methodBasedRoutes ) { foreach ( $ methodBasedRoutes as $ method => $ routes ) { if ( ! isset ( $ allowedMethods [ $ method ] ) && $ httpMethod !== '*' ) { continue ; } foreach ( $ routes as $ route ) { if ( ! $ route -> match ( $ request , $ variables , $ hostVariables ) ) { if ( $ hostVariables === null ) { continue 3 ; } continue ; } return $ route ; } } } } }

Routes a request.

@param array $request The request to route.


public function link($name, $params = [], $options = [])
    {
        $defaults = [
            'basePath' => $this->basePath()
        ];
        $options += $defaults;

        $params += $this->_defaults;

        if (!isset($this[$name])) {
            throw new RouterException("No binded route defined for `'{$name}'`, bind it first with `bind()`.");
        }
        $route = $this[$name];
        return $route->link($params, $options);
    }

Returns a route's link.

@param  string $name    A route name.
@param  array  $params  The route parameters.
@param  array  $options Options for generating the proper prefix. Accepted values are:
- `'absolute'` _boolean_: `true` or `false`.
- `'scheme'`   _string_ : The scheme.
- `'host'`     _string_ : The host name.
- `'basePath'` _string_ : The base path.
- `'query'`    _string_ : The query string.
- `'fragment'` _string_ : The fragment string.
@return string          The link.


public function clear()
    {
        $this->_basePath = '';
        $this->_strategies = [];
        $this->_defaults = [];
        $this->_routes = [];
        $scope = $this->_classes['scope'];
        $this->_scopes = [new $scope(['router' => $this])];
    }

public function clear ( ) { $ this -> _basePath = '' ; $ this -> _strategies = [ ] ; $ this -> _defaults = [ ] ; $ this -> _routes = [ ] ; $ scope = $ this -> _classes [ 'scope' ] ; $ this -> _scopes = [ new $ scope ( [ 'router' => $ this ] ) ] ; }


private function createJs()
    {
    	$nodes = $this->_workflow->getAllStatuses();
    	$trList = [];
    	$nodeList = [];
    	foreach($nodes as $node) {
    		$n = new \stdClass();
    		$n->id = $node->getId();
    		$n->label = $node->getLabel();
    		if( $node->getMetadata('color') ){
    			if( $node->getWorkflow()->getInitialStatusId() == $node->getId() ){
    				$n->borderWidth = 4;
    				$n->color = new \stdClass();
    				$n->color->border = 'rgb(0,255,42)';
    				// 	$n->color->background = $node->getMetadata('color');
    			} else {
    				//	$n->color = $node->getMetadata('color');
    			}
    		}
    		$nodeList[] = $n;

    		$transitions = $node->getTransitions();
    		foreach($transitions as $transition){
    			$t = new \stdClass();
    			$t->from = $n->id;
    			$t->to = $transition->getEndStatus()->getId();
    			$t->arrows = 'to';
    			$trList[] = $t;
    		}
    	}
    	$jsonNodes = \yii\helpers\Json::encode($nodeList);
    	$jsonTransitions = \yii\helpers\Json::encode($trList);

    	$js=<<<EOS
		var {$this->visNetworkId} = new vis.Network(
			document.getElementById('{$this->containerId}'),
	    	{
			    nodes: new vis.DataSet($jsonNodes),
			    edges: new vis.DataSet($jsonTransitions)
		  	},
	    	{
				"physics": {
					"solver": "repulsion"
				}
			}
	    );

EOS;
    	return $js;
    }

Creates and returns the JS code.
The JS code is used to initialize the VIS instances in charge of displaying the workflow.

@return string the JS code

Creates and returns the JS code . The JS code is used to initialize the VIS instances in charge of displaying the workflow .


public function get()
    {
        if (!$this->empty())
        {
            return $this->file->disk()->get(
                $this->hashName
            );
        }

        return null;
    }

public function get ( ) { if ( ! $ this -> empty ( ) ) { return $ this -> file -> disk ( ) -> get ( $ this -> hashName ) ; } return null ; }


private function getToken() {
        $data = array(
            'grant_type'    => 'client_credentials',
            'client_id'     => $this->userId,
            'client_secret' => $this->secret,
        );

        $requestResult = $this->sendRequest( 'oauth/access_token', 'POST', $data, false );

        if( $requestResult->http_code != 200 ) {
            return false;
        }

        $this->refreshToken = 0;
        $this->token = $requestResult->data->access_token;

        $this->storage->set($this->token);

        return true;
    }

private function getToken ( ) { $ data = array ( 'grant_type' => 'client_credentials' , 'client_id' => $ this -> userId , 'client_secret' => $ this -> secret , ) ; $ requestResult = $ this -> sendRequest ( 'oauth/access_token' , 'POST' , $ data , false ) ; if ( $ requestResult -> http_code != 200 ) { return false ; } $ this -> refreshToken = 0 ; $ this -> token = $ requestResult -> data -> access_token ; $ this -> storage -> set ( $ this -> token ) ; return true ; }


public function listAddressBooks( $limit = NULL, $offset = NULL ) {
        $data = array();
        if( !is_null( $limit ) ) {
            $data['limit'] = $limit;
        }
        if( !is_null( $offset ) ) {
            $data['offset'] = $offset;
        }

        $requestResult = $this->sendRequest( 'addressbooks', 'GET', $data );

        return $this->handleResult( $requestResult );
    }

public function listAddressBooks ( $ limit = NULL , $ offset = NULL ) { $ data = array ( ) ; if ( ! is_null ( $ limit ) ) { $ data [ 'limit' ] = $ limit ; } if ( ! is_null ( $ offset ) ) { $ data [ 'offset' ] = $ offset ; } $ requestResult = $ this -> sendRequest ( 'addressbooks' , 'GET' , $ data ) ; return $ this -> handleResult ( $ requestResult ) ; }

Get list of address books

@param null $limit
@param null $offset
@return mixed


public function getEmailsFromBook( $id ) {
        if( empty( $id ) ) {
            return $this->handleError( 'Empty book id' );
        }

        $requestResult = $this->sendRequest( 'addressbooks/' . $id . '/emails' );

        return $this->handleResult( $requestResult );
    }

public
function
getEmailsFromBook
(
$
id
)
{
if
(
empty
(
$
id
)
)
{
return
$
this
->
handleError
(
'Empty book id'
)
;
}
$
requestResult
=
$
this
->
sendRequest
(
'addressbooks/'
.
$
id
.
'/emails'
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

List email addresses from book

@param $id
@return mixed|stdClass


public function addEmails( $bookId, $emails ) {
        if( empty( $bookId ) || empty( $emails ) ) {
            return $this->handleError( 'Empty book id or emails' );
        }

        $data = array(
            'emails' => serialize( $emails )
        );

        $requestResult = $this->sendRequest( 'addressbooks/' . $bookId . '/emails', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public
function
addEmails
(
$
bookId
,
$
emails
)
{
if
(
empty
(
$
bookId
)
||
empty
(
$
emails
)
)
{
return
$
this
->
handleError
(
'Empty book id or emails'
)
;
}
$
data
=
array
(
'emails'
=>
serialize
(
$
emails
)
)
;
$
requestResult
=
$
this
->
sendRequest
(
'addressbooks/'
.
$
bookId
.
'/emails'
,
'POST'
,
$
data
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Add new emails to address book

@param $bookId
@param $emails
@return mixed|stdClass


public function campaignCost( $bookId ) {
        if( empty( $bookId ) ) {
            return $this->handleError( 'Empty book id' );
        }

        $requestResult = $this->sendRequest( 'addressbooks/' . $bookId . '/cost' );

        return $this->handleResult( $requestResult );
    }

public
function
campaignCost
(
$
bookId
)
{
if
(
empty
(
$
bookId
)
)
{
return
$
this
->
handleError
(
'Empty book id'
)
;
}
$
requestResult
=
$
this
->
sendRequest
(
'addressbooks/'
.
$
bookId
.
'/cost'
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Get cost of campaign based on address book

@param $bookId
@return mixed|stdClass


public function createCampaign( $senderName, $senderEmail, $subject, $body, $bookId, $name = '', $attachments = '' ) {
        if( empty( $senderName ) || empty( $senderEmail ) || empty( $subject ) || empty( $body ) || empty( $bookId ) ) {
            return $this->handleError( 'Not all data.' );
        }

        if( !empty( $attachments ) ) {
            $attachments = serialize( $attachments );
        }
        $data = array(
            'sender_name'  => $senderName,
            'sender_email' => $senderEmail,
            'subject'      => $subject,
            'body'         => base64_encode( $body ),
            'list_id'      => $bookId,
            'name'         => $name,
            'attachments'  => $attachments
        );

        $requestResult = $this->sendRequest( 'campaigns', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public
function
createCampaign
(
$
senderName
,
$
senderEmail
,
$
subject
,
$
body
,
$
bookId
,
$
name
=
''
,
$
attachments
=
''
)
{
if
(
empty
(
$
senderName
)
||
empty
(
$
senderEmail
)
||
empty
(
$
subject
)
||
empty
(
$
body
)
||
empty
(
$
bookId
)
)
{
return
$
this
->
handleError
(
'Not all data.'
)
;
}
if
(
!
empty
(
$
attachments
)
)
{
$
attachments
=
serialize
(
$
attachments
)
;
}
$
data
=
array
(
'sender_name'
=>
$
senderName
,
'sender_email'
=>
$
senderEmail
,
'subject'
=>
$
subject
,
'body'
=>
base64_encode
(
$
body
)
,
'list_id'
=>
$
bookId
,
'name'
=>
$
name
,
'attachments'
=>
$
attachments
)
;
$
requestResult
=
$
this
->
sendRequest
(
'campaigns'
,
'POST'
,
$
data
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Create new campaign

@param $senderName
@param $senderEmail
@param $subject
@param $body
@param $bookId
@param string $name
@param string $attachments
@return mixed


public function addSender( $senderName, $senderEmail ) {
        if( empty( $senderName ) || empty( $senderEmail ) ) {
            return $this->handleError( 'Empty sender name or email' );
        }

        $data = array(
            'email' => $senderEmail,
            'name'  => $senderName
        );

        $requestResult = $this->sendRequest( 'senders', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public
function
addSender
(
$
senderName
,
$
senderEmail
)
{
if
(
empty
(
$
senderName
)
||
empty
(
$
senderEmail
)
)
{
return
$
this
->
handleError
(
'Empty sender name or email'
)
;
}
$
data
=
array
(
'email'
=>
$
senderEmail
,
'name'
=>
$
senderName
)
;
$
requestResult
=
$
this
->
sendRequest
(
'senders'
,
'POST'
,
$
data
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Add new sender

@param $senderName
@param $senderEmail
@return mixed|stdClass


public function activateSender( $email, $code ) {
        if( empty( $email ) || empty( $code ) ) {
            return $this->handleError( 'Empty email or activation code' );
        }

        $data = array(
            'code' => $code
        );

        $requestResult = $this->sendRequest( 'senders/' . $email . '/code', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public
function
activateSender
(
$
email
,
$
code
)
{
if
(
empty
(
$
email
)
||
empty
(
$
code
)
)
{
return
$
this
->
handleError
(
'Empty email or activation code'
)
;
}
$
data
=
array
(
'code'
=>
$
code
)
;
$
requestResult
=
$
this
->
sendRequest
(
'senders/'
.
$
email
.
'/code'
,
'POST'
,
$
data
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Activate sender using code

@param $email
@param $code
@return mixed|stdClass


public function pushListWebsiteSubscriptions( $websiteId, $limit = NULL, $offset = NULL ) {
        $data = array();
        if( !is_null( $limit ) ) {
            $data['limit'] = $limit;
        }
        if( !is_null( $offset ) ) {
            $data['offset'] = $offset;
        }

        $requestResult = $this->sendRequest( 'push/websites/'.$websiteId.'/subscriptions', 'GET', $data );

        return $this->handleResult( $requestResult );
    }

public function pushListWebsiteSubscriptions ( $ websiteId , $ limit = NULL , $ offset = NULL ) { $ data = array ( ) ; if ( ! is_null ( $ limit ) ) { $ data [ 'limit' ] = $ limit ; } if ( ! is_null ( $ offset ) ) { $ data [ 'offset' ] = $ offset ; } $ requestResult = $ this -> sendRequest ( 'push/websites/' . $ websiteId . '/subscriptions' , 'GET' , $ data ) ; return $ this -> handleResult ( $ requestResult ) ; }

Get list of subscriptions for the website

@param $websiteId
@return mixed


public function pushSetSubscriptionState( $subscriptionId, $stateValue ) {
        $data = array(
            'id' => $subscriptionId,
            'state' => $stateValue
        );

        $requestResult = $this->sendRequest( 'push/subscriptions/state', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public function pushSetSubscriptionState ( $ subscriptionId , $ stateValue ) { $ data = array ( 'id' => $ subscriptionId , 'state' => $ stateValue ) ; $ requestResult = $ this -> sendRequest ( 'push/subscriptions/state' , 'POST' , $ data ) ; return $ this -> handleResult ( $ requestResult ) ; }

Set state for subscription

@param $subscriptionId
@param $stateValue
@return mixed


public function createPushTask( $taskInfo, $additionalParams = array() ) {
        $data = $taskInfo;
        if (!isset($data['ttl'])) {
            $data['ttl'] = 0;
        }
        if( empty($data['title']) || empty($data['website_id']) || empty($data['body']) ) {
            return $this->handleError( 'Not all data' );
        }
        if ($additionalParams) {
            foreach($additionalParams as $key=>$val) {
                $data[$key] = $val;
            }
        }

        $requestResult = $this->sendRequest( '/push/tasks', 'POST', $data );

        return $this->handleResult( $requestResult );
    }

public
function
createPushTask
(
$
taskInfo
,
$
additionalParams
=
array
(
)
)
{
$
data
=
$
taskInfo
;
if
(
!
isset
(
$
data
[
'ttl'
]
)
)
{
$
data
[
'ttl'
]
=
0
;
}
if
(
empty
(
$
data
[
'title'
]
)
||
empty
(
$
data
[
'website_id'
]
)
||
empty
(
$
data
[
'body'
]
)
)
{
return
$
this
->
handleError
(
'Not all data'
)
;
}
if
(
$
additionalParams
)
{
foreach
(
$
additionalParams
as
$
key
=>
$
val
)
{
$
data
[
$
key
]
=
$
val
;
}
}
$
requestResult
=
$
this
->
sendRequest
(
'/push/tasks'
,
'POST'
,
$
data
)
;
return
$
this
->
handleResult
(
$
requestResult
)
;
}

Create new push campaign

@param $taskInfo
@param array $additionalParams
@return mixed|stdClass


protected function hashName()
    {
        $userId = $this->app['config']->get('sendpulse.api_user_id');
        $secret = $this->app['config']->get('sendpulse.api_secret');

        return md5($userId . '::' . $secret);
    }

protected function hashName ( ) { $ userId = $ this -> app [ 'config' ] -> get ( 'sendpulse.api_user_id' ) ; $ secret = $ this -> app [ 'config' ] -> get ( 'sendpulse.api_secret' ) ; return md5 ( $ userId . '::' . $ secret ) ; }


public function sendToWebsite($url, array $params)
    {
        // Sending request
        $client  = $this->getClient();
        $response = $client->request('POST', $url, [
            'query' => http_build_query($params, '', '&')
        ]);

        // Getting response body
        $responseString = $response->getBody()->getContents();
        $responseString = trim($responseString);

        return $responseString;
    }

public
function
sendToWebsite
(
$
url
,
array
$
params
)
{
// Sending request
$
client
=
$
this
->
getClient
(
)
;
$
response
=
$
client
->
request
(
'POST'
,
$
url
,
[
'query'
=>
http_build_query
(
$
params
,
''
,
'&'
)
]
)
;
// Getting response body
$
responseString
=
$
response
->
getBody
(
)
->
getContents
(
)
;
$
responseString
=
trim
(
$
responseString
)
;
return
$
responseString
;
}

Sends a query to the provided url and return the response body.

@param string $url
@param array  $params

@return string

Sends a query to the provided url and return the response body .


public function sendToApi($url, array $params, $responseType = self::RESPONSE_NEW_LINE, array $notDecode = null, $forceArray = array())
    {
        $this->preSendToApiCheck();

        // Merging post-data
        $fields                  = array();
        $fields['loginName']     = $this->getAccount()->getLoginName();
        $fields['loginPassword'] = $this->getAccount()->getLoginPassword();
        $fields                  = array_merge($fields, $params);

        // Sending request
        $client   = $this->getClient();
        $response = $client->request(
            'POST',
            $url,
            ['form_params' => $fields]
        );
        $query    = http_build_query($params);

        // Getting response body
        $responseString = $response->getBody()->getContents();
        $responseString = trim($responseString);

        // Decoding and returning response
        if ($responseType == self::RESPONSE_NEW_LINE) {
            return $this->decodeNewLineEncodedResponse($responseString, $query, $forceArray);
        } else {
            return $this->decodeUrlEncodedResponse($responseString, $query, $notDecode, $forceArray);
        }
    }

public
function
sendToApi
(
$
url
,
array
$
params
,
$
responseType
=
self
::
RESPONSE_NEW_LINE
,
array
$
notDecode
=
,
$
forceArray
=
array
(
)
)
{
$
this
->
preSendToApiCheck
(
)
;
// Merging post-data
$
fields
=
array
(
)
;
$
fields
[
'loginName'
]
=
$
this
->
getAccount
(
)
->
getLoginName
(
)
;
$
fields
[
'loginPassword'
]
=
$
this
->
getAccount
(
)
->
getLoginPassword
(
)
;
$
fields
=
array_merge
(
$
fields
,
$
params
)
;
// Sending request
$
client
=
$
this
->
getClient
(
)
;
$
response
=
$
client
->
request
(
'POST'
,
$
url
,
[
'form_params'
=>
$
fields
]
)
;
$
query
=
http_build_query
(
$
params
)
;
// Getting response body
$
responseString
=
$
response
->
getBody
(
)
->
getContents
(
)
;
$
responseString
=
trim
(
$
responseString
)
;
// Decoding and returning response
if
(
$
responseType
==
self
::
RESPONSE_NEW_LINE
)
{
return
$
this
->
decodeNewLineEncodedResponse
(
$
responseString
,
$
query
,
$
forceArray
)
;
}
else
{
return
$
this
->
decodeUrlEncodedResponse
(
$
responseString
,
$
query
,
$
notDecode
,
$
forceArray
)
;
}
}

Send a request to the comodo API, and decodes the response as given

@param string     $url
@param array      $params
@param int        $responseType
@param array|null $notDecode
@param array      $forceArray

@return array|bool

Send a request to the comodo API and decodes the response as given


protected function preSendToApiCheck()
    {
        if ($this->getAccount() === null) {
            throw new \Exception('Please provided an account');
        }

        if (!$this->getAccount()->isValid()) {
            throw new \Exception('Please provided valid account');
        }

        return true;
    }

protected
function
preSendToApiCheck
(
)
{
if
(
$
this
->
getAccount
(
)
===
)
{
throw
new
\
Exception
(
'Please provided an account'
)
;
}
if
(
!
$
this
->
getAccount
(
)
->
isValid
(
)
)
{
throw
new
\
Exception
(
'Please provided valid account'
)
;
}
return
true
;
}

Checks, if a valid account has been provided

@return bool
@throws \Exception

Checks if a valid account has been provided