private function doPersist()
    {
        if (!$this->model->getMeta(ModelInterface::IS_CHANGED)) {
            return;
        }

        $this->handlePrePersist();

        // TO DO: manual sorting property handling is not enabled here as it originates from the backend defininiton.
        // Save the model.
        $dataProvider = $this->environment->getDataProvider($this->model->getProviderName());

        $dataProvider->save($this->model);

        $this->handlePostPersist();

        $this->storeVersion($this->model);
    }

Handle the persisting of the currently loaded model.

@return void

Handle the persisting of the currently loaded model .


protected function configureCas( $method = 'client' ) {
		if ( $this->config['cas_enable_saml'] ) {
			$server_type = SAML_VERSION_1_1;
		} else {
			// This allows the user to use 1.0, 2.0, etc as a string in the config
			$cas_version_str = 'CAS_VERSION_' . str_replace( '.', '_',
					$this->config['cas_version'] );

			// We pull the phpCAS constant values as this is their definition
			// PHP will generate a E_WARNING if the version string is invalid which is helpful for troubleshooting
			$server_type = constant( $cas_version_str );

			if ( is_null( $server_type ) ) {
				// This will never be null, but can be invalid values for which we need to detect and substitute.
				phpCAS::log( 'Invalid CAS version set; Reverting to defaults' );
				$server_type = CAS_VERSION_2_0;
			}
		}

		phpCAS::$method( $server_type, $this->config['cas_hostname'],
			(int) $this->config['cas_port'],
			$this->config['cas_uri'], $this->config['cas_control_session'] );

		if ( $this->config['cas_enable_saml'] ) {
			// Handle SAML logout requests that emanate from the CAS host exclusively.
			// Failure to restrict SAML logout requests to authorized hosts could
			// allow denial of service attacks where at the least the server is
			// tied up parsing bogus XML messages.
			phpCAS::handleLogoutRequests( true,
				explode( ',', $this->config['cas_real_hosts'] ) );
		}
	}

Configure CAS Client|Proxy

@param $method


protected function parseConfig( array $config ) {

		$defaults = [
			'cas_hostname'         => '',
			'cas_session_name'     => 'CASAuth',
			'cas_session_lifetime' => 7200,
			'cas_session_path'     => '/',
			'cas_control_session'  => false,
			'cas_session_httponly' => true,
			'cas_port'             => 443,
			'cas_uri'              => '/cas',
			'cas_validation'       => '',
			'cas_cert'             => '',
			'cas_proxy'            => false,
			'cas_validate_cn'      => true,
			'cas_login_url'        => '',
			'cas_logout_url'       => 'https://cas.myuniv.edu/cas/logout',
			'cas_logout_redirect'  => '',
			'cas_redirect_path'    => '',
			'cas_enable_saml'      => true,
			'cas_version'          => "2.0",
			'cas_debug'            => false,
			'cas_verbose_errors'   => false,
			'cas_masquerade'       => ''
		];

		$this->config = array_merge( $defaults, $config );
	}

protected function parseConfig ( array $ config ) { $ defaults = [ 'cas_hostname' => '' , 'cas_session_name' => 'CASAuth' , 'cas_session_lifetime' => 7200 , 'cas_session_path' => '/' , 'cas_control_session' => false , 'cas_session_httponly' => true , 'cas_port' => 443 , 'cas_uri' => '/cas' , 'cas_validation' => '' , 'cas_cert' => '' , 'cas_proxy' => false , 'cas_validate_cn' => true , 'cas_login_url' => '' , 'cas_logout_url' => 'https://cas.myuniv.edu/cas/logout' , 'cas_logout_redirect' => '' , 'cas_redirect_path' => '' , 'cas_enable_saml' => true , 'cas_version' => "2.0" , 'cas_debug' => false , 'cas_verbose_errors' => false , 'cas_masquerade' => '' ] ; $ this -> config = array_merge ( $ defaults , $ config ) ; }

Maintain backwards compatibility with config file

@param array $config


protected function configureCasValidation() {
		if ( $this->config['cas_validation'] == 'ca'
		     || $this->config['cas_validation'] == 'self' ) {
			phpCAS::setCasServerCACert( $this->config['cas_cert'],
				$this->config['cas_validate_cn'] );
		} else {
			// Not safe (does not validate your CAS server)
			phpCAS::setNoCasServerValidation();
		}
	}

Configure SSL Validation

Having some kind of server cert validation in production
is highly recommended.


public function getAttribute( $key ) {
		if ( ! $this->isMasquerading() ) {
			return phpCAS::getAttribute( $key );
		}
		if ( $this->hasAttribute( $key ) ) {
			return $this->_attributes[ $key ];
		}

		return;
	}

public function getAttribute ( $ key ) { if ( ! $ this -> isMasquerading ( ) ) { return phpCAS :: getAttribute ( $ key ) ; } if ( $ this -> hasAttribute ( $ key ) ) { return $ this -> _attributes [ $ key ] ; } return ; }

Retrieve a specific attribute by key name.  The
attribute returned can be either a string or
an array based on matches.

@param $key

@return mixed

Retrieve a specific attribute by key name . The attribute returned can be either a string or an array based on matches .


public function hasAttribute( $key ) {
		if ( $this->isMasquerading() ) {
			return array_key_exists( $key, $this->_attributes );
		}

		return phpCAS::hasAttribute( $key );
	}

public function hasAttribute ( $ key ) { if ( $ this -> isMasquerading ( ) ) { return array_key_exists ( $ key , $ this -> _attributes ) ; } return phpCAS :: hasAttribute ( $ key ) ; }

Check for the existence of a key in attributes.

@param $key

@return boolean

Check for the existence of a key in attributes .


public function logout( $url = '', $service = '' ) {
		if ( phpCAS::isSessionAuthenticated() ) {
			if ( isset( $_SESSION['phpCAS'] ) ) {
				$serialized = serialize( $_SESSION['phpCAS'] );
				phpCAS::log( 'Logout requested, but no session data found for user:'
				             . PHP_EOL . $serialized );
			}
		}
		$params = [];
		if ( $service ) {
			$params['service'] = $service;
		} elseif ( $this->config['cas_logout_redirect'] ) {
			$params['service'] = $this->config['cas_logout_redirect'];
		}
		if ( $url ) {
			$params['url'] = $url;
		}
		phpCAS::logout( $params );
		exit;
	}

Logout of the CAS session and redirect users.

@param string $url
@param string $service

Logout of the CAS session and redirect users .


private function setCode($code)
    {
        if (!\is_numeric($code)) {
            throw InvalidStatusCodeException::notNumeric($code);
        }
        $code = (int) $code;

        if ($code < 100) {
            throw InvalidStatusCodeException::notGreaterOrEqualTo100($code);
        }
        $this->code = $code;
    }

private function setCode ( $ code ) { if ( ! \ is_numeric ( $ code ) ) { throw InvalidStatusCodeException :: notNumeric ( $ code ) ; } $ code = ( int ) $ code ; if ( $ code < 100 ) { throw InvalidStatusCodeException :: notGreaterOrEqualTo100 ( $ code ) ; } $ this -> code = $ code ; }

Set the code. Used in constructor to ensure the code meets the
requirements for a status code.

@param int $code The status code
@throws InvalidStatusCodeException If the status code is invalid

Set the code . Used in constructor to ensure the code meets the requirements for a status code .


protected function getKeyOrNull($model)
    {
        if ($model == null) {
            return null;
        }
        return $model->{self::ROW_NUM_COLUMN} ?: ($model instanceof Model ? $model->getKey() : null);
    }

protected function getKeyOrNull ( $ model ) { if ( $ model == null ) { return null ; } return $ model -> { self :: ROW_NUM_COLUMN } ? : ( $ model instanceof Model ? $ model -> getKey ( ) : null ) ; }

Try to get model row number or key. Return row number column if exists.

Try to get model row number or key . Return row number column if exists .


protected function isIntegerKey($current, $model): bool
    {
        if ($model != null && $model instanceof Model) {
            return !empty($model->{self::ROW_NUM_COLUMN}) || $model->getKeyType() == 'int';
        } else {
            if ($current != null && is_numeric($current) || ctype_digit($current)) {
                return true;
            }
        }
        return false;
    }

protected function isIntegerKey ( $ current , $ model ) : bool { if ( $ model != null && $ model instanceof Model ) { return ! empty ( $ model -> { self :: ROW_NUM_COLUMN } ) || $ model -> getKeyType ( ) == 'int' ; } else { if ( $ current != null && is_numeric ( $ current ) || ctype_digit ( $ current ) ) { return true ; } } return false ; }

Detect, if cursor value is integer or not.
Extract key type from model, if possible, otherwise just check cursor value type

@param mixed $current Current curor value
@param mixed $model one of items or null
@return boolean

Detect if cursor value is integer or not . Extract key type from model if possible otherwise just check cursor value type


protected function getFragmentsFromUrl()
        {

            // Return null on empty request path
            if (\Environment::get('request') == '') {
                return null;
            }

            $test = \Environment::get('request');

            // Get the request string without the index.php fragment
            if (\Environment::get('request') == $this->_sApiUrl . 'index.php') {
                $strRequest = '';
            } else {
                list($strRequest) = explode('?', str_replace($this->_sApiUrl . 'index.php/', '', \Environment::get('request')), 2);
            }

            // Remove api fragment
            if (substr($strRequest, 0, strlen($this->_sApiUrl)) == $this->_sApiUrl) {
                $strRequest = substr($strRequest, strlen($this->_sApiUrl));
            }

            // URL decode here
            $strRequest = rawurldecode($strRequest);
            $strRequest = substr($strRequest,1);

            // return the fragments
            return explode('/', $strRequest);
        }

Split the request into fragments and find the api resource


public function addContainersFromArray(array $array) {
        foreach ($array as $value) {
            $container = new C4GContainer();
            foreach ($value as $k => $v) {
                $container->addElement($v, $k);
            }
            $this->addElement($container);
        }
    }

public function addContainersFromArray ( array $ array ) { foreach ( $ array as $ value ) { $ container = new C4GContainer ( ) ; foreach ( $ value as $ k => $ v ) { $ container -> addElement ( $ v , $ k ) ; } $ this -> addElement ( $ container ) ; } }

Add a two-dimensional array to the container, where every outer array element becomes a container
and every inner array element becomes an element of the corresponding container.
@param array $array
@throws \Exception

Add a two - dimensional array to the container where every outer array element becomes a container and every inner array element becomes an element of the corresponding container .


public function buildQuery()
    {
        $wrappedQuery = $this->wrapWithRowCounter($this->originalQuery);
        $query = $this->getFakeModelQuery($wrappedQuery);

        $query->where($this->idKey, '>', $this->cursorRequest->current)
            ->take($this->cursorRequest->pageSize);
        return $query;
    }

public function buildQuery ( ) { $ wrappedQuery = $ this -> wrapWithRowCounter ( $ this -> originalQuery ) ; $ query = $ this -> getFakeModelQuery ( $ wrappedQuery ) ; $ query -> where ( $ this -> idKey , '>' , $ this -> cursorRequest -> current ) -> take ( $ this -> cursorRequest -> pageSize ) ; return $ query ; }

Build a query, which will return only one page from original data set, matching cursor parameters

@return EloquentBuilder|QueryBuilder

Build a query which will return only one page from original data set matching cursor parameters


protected function wrapWithRowCounter($originalQuery)
    {
        $tmpQuery = $originalQuery->cloneWithoutBindings(['where'])
            ->crossJoin(DB::raw('(SELECT @row := 0) as row_id_fake_table'));

        return DB::table(
            DB::raw("(SELECT *, (@row := @row+1) as {$this->idKey} FROM (" . $tmpQuery->toSql() . ") as t1) as t2")
        )->mergeBindings($originalQuery);
    }

Add statement, which will include number of rows in original data set into query, which returns one page

@param EloquentBuilder|QueryBuilder $originalQuery Query, that retuns original data set to paginate
@return QueryBuilder

Add statement which will include number of rows in original data set into query which returns one page


protected function getFakeModelQuery($wrappedQuery)
    {
        /**
         * Clone of original Eloquent model, which we can modify to apply some hacks to build specific query
         *
         * @var Model $fakeModel
         */
        $fakeModel = new $this->model;
        $fakeModel->setTable(DB::raw("(" . $wrappedQuery->toSql() . ") AS " . $this->model->getTable()));

        /**
         * Query builder
         *
         * @var EloquentBuilder $modelQuery
         */
        $modelQuery = $fakeModel->newQueryWithoutScopes();
        $builder = Query::getBaseQuery($modelQuery);
        $builder->columns = null; // We always select everything from subquery
        $modelQuery->setQuery($builder->cloneWithoutBindings(['select', 'where'])); // remove default bindings
        $modelQuery->mergeBindings($wrappedQuery);
        return $modelQuery;
    }

Buld query around model clone without scopes, that may affect query result.

@param QueryBuilder $wrappedQuery Query to actually perform
@return EloquentBuilder|QueryBuilder

Buld query around model clone without scopes that may affect query result .


public static function generateActivationLinkFromKey($key,$keyAction='')
	{
		// check if key exists
		if (empty( $key )) {
			return false;
		}

		// get action for this key
        if (!$keyAction) {
            $keyAction = C4gActivationkeyModel::getActionForKey($key);
        }

		$keyAction = explode(':', $keyAction);

		// find an appropriate activationpage
		//
		// try to find a page with a specific handler for the key-action
        $db = \Database::getInstance();
        $objActivationPages = $db->prepare("SELECT * FROM tl_content WHERE type=? AND c4g_activationpage_action_handler=?")
            ->execute('c4g_activationpage', $keyAction[0]);

        if (!$objActivationPages) {
            // if no page was found, try to find pages with automatic-handlers
            $db = \Database::getInstance();
            $objActivationPages = $db->prepare("SELECT * FROM tl_content WHERE type=? AND c4g_activationpage_action_handler=?")
                ->execute('c4g_activationpage', '');

            // if still no page is found, the function failed
            if (!$objActivationPages) {
                return false;
            }
        }

		// use the first page (even if more pages are found)
		$objActivationPages->next();

		// get the article for this content-element
		$objArticle = \ArticleModel::findByPk( $objActivationPages->pid );
		if ($objArticle) {
			// if found, find the Page, where this article is nested
			$objPage = \PageModel::findByPk( $objArticle->pid );
			if ($objPage) {
				// if found build the desired URL (base + page-url + key)
				return \Environment::get('base') . \Controller::generateFrontendUrl( $objPage->row() ) . '?key=' . $key;
			}
		}

		// article or page not found
		return false;
	}

generates an activationlink from geiven key
@param  string $key
@return string


public static function assignUserToKey( $userId, $key )
	{
		$objKey = C4gActivationkeyModel::findBy( 'activationkey', hash('sha256', $key) );
		if (empty( $objKey ) || $objKey->used_by != 0) { return false; }
		$objKey->used_by = $userId;
		$objKey->save();
		return true;
	}

public static function assignUserToKey ( $ userId , $ key ) { $ objKey = C4gActivationkeyModel :: findBy ( 'activationkey' , hash ( 'sha256' , $ key ) ) ; if ( empty ( $ objKey ) || $ objKey -> used_by != 0 ) { return false ; } $ objKey -> used_by = $ userId ; $ objKey -> save ( ) ; return true ; }

assigns an user to a key, if not already claimed
@param  int $userId
@param  string $key
@return boolean

assigns an user to a key if not already claimed


public static function keyIsValid( $key )
	{
		$key = C4gActivationkeyModel::findOneBy( 'activationkey', hash('sha256', $key) );
		// the key exists, is not already claimed and is not expired
		return (!empty( $key ) && empty( $key->used_by ) && ($key->expiration_date == 0 || $key->expiration_date > time()));
	}

returns the action connected to the given key
@param  string $key
@return string


protected function readPaging(Request $request): PagingInfo
    {
        $input = $request->only(PagingInfo::KEYS);
        if (isset($input[PAGE_SIZE])) {
            $pageSize = (int)$input[PAGE_SIZE];
            if ($pageSize <= 0) {
                $input[PAGE_SIZE] = config(API_PAGE_SIZE_MAX);
            }
            if ($pageSize > config(API_PAGE_SIZE_MAX)) {
                $input[PAGE_SIZE] = config(API_PAGE_SIZE_MAX);
            }
        }
        return new PagingInfo($input);
    }

protected function readPaging ( Request $ request ) : PagingInfo { $ input = $ request -> only ( PagingInfo :: KEYS ) ; if ( isset ( $ input [ PAGE_SIZE ] ) ) { $ pageSize = ( int ) $ input [ PAGE_SIZE ] ; if ( $ pageSize <= 0 ) { $ input [ PAGE_SIZE ] = config ( API_PAGE_SIZE_MAX ) ; } if ( $ pageSize > config ( API_PAGE_SIZE_MAX ) ) { $ input [ PAGE_SIZE ] = config ( API_PAGE_SIZE_MAX ) ; } } return new PagingInfo ( $ input ) ; }

Read request paging data

If checking value specified, allows only integer positive value equal or less 100 (setting).
If value not specified, take the default value from settings.

@param Request $request raw request data
@return PagingInfo


protected static function registerTemplates($objFiles)
    {
        foreach ($objFiles as $varFile) {
            $strFile = (is_array($varFile)) ? array_shift($varFile) : $varFile;
            $objFile = pathinfo($strFile);
            \TemplateLoader::addFile($objFile['filename'], str_replace(TL_ROOT . '/', '', $objFile['dirname']));
        }
    }

protected static function registerTemplates ( $ objFiles ) { foreach ( $ objFiles as $ varFile ) { $ strFile = ( is_array ( $ varFile ) ) ? array_shift ( $ varFile ) : $ varFile ; $ objFile = pathinfo ( $ strFile ) ; \ TemplateLoader :: addFile ( $ objFile [ 'filename' ] , str_replace ( TL_ROOT . '/' , '' , $ objFile [ 'dirname' ] ) ) ; } }

Registriert die gefundenen Templates bei Contao.
@param $objFiles

Registriert die gefundenen Templates bei Contao .


private function registerCustomHandlers()
    {
        API::error(function (UnauthorizedHttpException $e) {
            return $this->handleUnauthorized($e);
        });
        API::error(function (AuthorizationException $e) {
            return $this->handleAuthorizationError($e);
        });
        Api::error(function (PermissionsException $e) {
            return $this->handleAuthorizationError($e);
        });
        API::error(function (ValidationException $e) {
            return $this->handleValidation($e);
        });
        API::error(function (ModelNotFoundException $e) {
            return $this->handleModelNotFound($e);
        });
    }

private function registerCustomHandlers ( ) { API :: error ( function ( UnauthorizedHttpException $ e ) { return $ this -> handleUnauthorized ( $ e ) ; } ) ; API :: error ( function ( AuthorizationException $ e ) { return $ this -> handleAuthorizationError ( $ e ) ; } ) ; Api :: error ( function ( PermissionsException $ e ) { return $ this -> handleAuthorizationError ( $ e ) ; } ) ; API :: error ( function ( ValidationException $ e ) { return $ this -> handleValidation ( $ e ) ; } ) ; API :: error ( function ( ModelNotFoundException $ e ) { return $ this -> handleModelNotFound ( $ e ) ; } ) ; }

Register certain handlers via Dingo\API facade

We can't pass class method as callback directly,
so we wrap them into closures.

Register certain handlers via Dingo \ API facade


public function handleAuthorizationError(\Exception $e)
    {
        $e = new AccessDeniedHttpException($e->getMessage(), $e);
        return $this->handle($e);
    }

public function handleAuthorizationError ( \ Exception $ e ) { $ e = new AccessDeniedHttpException ( $ e -> getMessage ( ) , $ e ) ; return $ this -> handle ( $ e ) ; }

Security gateway throws AuthorizationException without HTTP code set.
Render AccessDeniedHttpException instead to produce 403 HTTP code instead of 500

@param \Exception $e Original exception to wrap and handle
@return Response

Security gateway throws AuthorizationException without HTTP code set . Render AccessDeniedHttpException instead to produce 403 HTTP code instead of 500


public function handleValidation(ValidationException $e)
    {
        $e = new CustomValidationException($e->validator->getMessageBag(), $e->getMessage(), $e, [], $e->getCode());
        return $this->handle($e);
    }

public function handleValidation ( ValidationException $ e ) { $ e = new CustomValidationException ( $ e -> validator -> getMessageBag ( ) , $ e -> getMessage ( ) , $ e , [ ] , $ e -> getCode ( ) ) ; return $ this -> handle ( $ e ) ; }

Dingo API does not handle default Laravel validation exception.
Wrap it into ValidationHttpException, processed properly

@param ValidationException $e Original exception to wrap and handle
@return Response

Dingo API does not handle default Laravel validation exception . Wrap it into ValidationHttpException processed properly


private function handleModelNotFound(ModelNotFoundException $e)
    {
        $e = new NotFoundHttpException($e->getMessage(), $e, $e->getCode());
        return $this->handle($e);
    }

private function handleModelNotFound ( ModelNotFoundException $ e ) { $ e = new NotFoundHttpException ( $ e -> getMessage ( ) , $ e , $ e -> getCode ( ) ) ; return $ this -> handle ( $ e ) ; }

Replace model not found exception to guarantee 404 error instead of 500

@param ModelNotFoundException $e Original exception to wrap and handle
@return Response


public function pop()
    {
        $data = $this->top();

        if (is_array($data) && count($data)) {
            $query = 'DELETE FROM `' . $this->table . '` WHERE `id` = ' . $data["id"];
            $this->execute($query);
            return $data;
        }

        return array();
    }

public
function
pop
(
)
{
$
data
=
$
this
->
top
(
)
;
if
(
is_array
(
$
data
)
&&
count
(
$
data
)
)
{
$
query
=
'DELETE FROM `'
.
$
this
->
table
.
'` WHERE `id` = '
.
$
data
[
"id"
]
;
$
this
->
execute
(
$
query
)
;
return
$
data
;
}
return
array
(
)
;
}

Entfernt ein Element vom Stack.
@return array|mixed


private function getComponents($skipCache = false)
    {
        $url = 'http://bower-component-list.herokuapp.com';
        $componentsFilePath = Yii::getAlias('@runtime/bower-cache/components.list');

        if (!$skipCache && is_file($componentsFilePath) && (time() - filemtime($componentsFilePath) < 60 * 60 * 6)) { // 6 hours
            $raw = file_get_contents($componentsFilePath);
        } else {
            $result = (new \GuzzleHttp\Client())->request('GET', $url);
            $raw = $result->getBody();
            FileHelper::createDirectory(dirname($componentsFilePath));
            file_put_contents($componentsFilePath, $raw);
        }

        return Json::decode($raw);
    }

Gets components array from bower API.

@param bool $skipCache whether to skip using local cache
@return array


private function attachEventHandlers()
    {
        $out = function ($string) {
            $this->stdout(Console::renderColoredString($string));
        };

        Event::on(Queue::class, Queue::EVENT_BEFORE_EXEC, function ($event) use ($out) {
            /** @var JobEvent $event */
            $out("%GNew job%n '" . get_class($event->job) . "'\n");
            $this->ensureLimits();
        });

        Event::on(Queue::class, Queue::EVENT_AFTER_EXEC, function ($event) use ($out) {
            /** @var JobEvent $event */
            $out("%GJob%n '" . get_class($event->job) . "' %Gis completed%n\n");
        });

        Event::on(Queue::class, Queue::EVENT_AFTER_ERROR, function ($event) use ($out) {
            /** @var ErrorEvent $event */
            $out("%RJob '" . get_class($event->job) . "' finished with error:%n '" . $event->error . "'\n");
        });

        Event::on(Queue::class, CliQueue::EVENT_WORKER_LOOP, function (\yii\queue\cli\WorkerEvent $event) use ($out) {
            $exitCode = $this->ensureLimits();
            if ($exitCode !== null) {
                $out('Reached limit of ' . static::MAX_EXECUTED_JOBS . " executed jobs. Stopping process.\n");
                $event->exitCode = $exitCode;
            }
        });

        Event::on(AbstractPackageCommand::class, AbstractPackageCommand::EVENT_BEFORE_RUN, function ($event) use ($out) {
            /** @var AbstractPackageCommand $command */
            $command = $event->sender;
            $out('%g[' . get_class($command) . ']%n Working on package %N' . $command->getPackage()->getFullName() . "%n\n");
        });
    }


public function request($method, $uri = '', array $options = [])
    {
        if (!isset($options['query'])) {
            $options['query'] = [];
        }
        if ($this->apiKey && !isset($options['query']['api_key'])) {
            $options['query']['api_key'] = $this->apiKey;
        }

        try {
            return $this->client->request($method, $uri, $options);
        } catch (\GuzzleHttp\Exception\BadResponseException $ex) {
            if ($ex->hasResponse()) {
                return $ex->getResponse();
            }
            throw $ex;
        }
    }

public function request ( $ method , $ uri = '' , array $ options = [ ] ) { if ( ! isset ( $ options [ 'query' ] ) ) { $ options [ 'query' ] = [ ] ; } if ( $ this -> apiKey && ! isset ( $ options [ 'query' ] [ 'api_key' ] ) ) { $ options [ 'query' ] [ 'api_key' ] = $ this -> apiKey ; } try { return $ this -> client -> request ( $ method , $ uri , $ options ) ; } catch ( \ GuzzleHttp \ Exception \ BadResponseException $ ex ) { if ( $ ex -> hasResponse ( ) ) { return $ ex -> getResponse ( ) ; } throw $ ex ; } }

Send request to server with api_key and return a Response.
@param string $method
@param string $uri
@param array $options
@throws \GuzzleHttp\Exception\BadResponseException
@return \GuzzleHttp\Psr7\Response

Send request to server with api_key and return a Response .


public function isAvailable()
    {
        $package = AssetPackage::fromFullName($this->getFullName());

        $repository = Yii::createObject(PackageRepository::class, []);

        return $repository->exists($package);
    }

public function isAvailable ( ) { $ package = AssetPackage :: fromFullName ( $ this -> getFullName ( ) ) ; $ repository = Yii :: createObject ( PackageRepository :: class , [ ] ) ; return $ repository -> exists ( $ package ) ; }

Check the package exists in Asset-Packagist.
@return boolean

Check the package exists in Asset - Packagist .


public function actionSyncToDb()
    {
        $packages = $this->packageStorage->listPackages();

        foreach ($packages as $name => $data) {
            $message = "Package %N$name%n ";
            $package = AssetPackage::fromFullName($name);
            $package->load();

            $message .= $this->packageRepository->exists($package)
                ? 'already exists. %BUpdated.%n'
                : 'does not exist. %GCreated.%n';

            $this->packageRepository->save($package);

            $this->stdout(Console::renderColoredString($message . "\n"));
        }
    }

public
function
actionSyncToDb
(
)
{
$
packages
=
$
this
->
packageStorage
->
listPackages
(
)
;
foreach
(
$
packages
as
$
name
=>
$
data
)
{
$
message
=
"Package %N$name%n "
;
$
package
=
AssetPackage
::
fromFullName
(
$
name
)
;
$
package
->
load
(
)
;
$
message
.=
$
this
->
packageRepository
->
exists
(
$
package
)
'already exists. %BUpdated.%n'
:
'does not exist. %GCreated.%n'
;
$
this
->
packageRepository
->
save
(
$
package
)
;
$
this
->
stdout
(
Console
::
renderColoredString
(
$
message
.
"\n"
)
)
;
}
}

Synchronizes file system packages to the database.

Synchronizes file system packages to the database .


public function actionUpdateExpired()
    {
        $packages = $this->packageRepository->getExpiredForUpdate();

        foreach ($packages as $package) {
            $package->load();
            Yii::$app->queue->push(Yii::createObject(PackageUpdateCommand::class, [$package]));

            $message = 'Package %N' . $package->getFullName() . '%n';
            $message .= ' was updated ' . Yii::$app->formatter->asRelativeTime($package->getUpdateTime());
            $message .= ". %GAdded to queue for update%n\n";
            $this->stdout(Console::renderColoredString($message));
        }
    }

public
function
actionUpdateExpired
(
)
{
$
packages
=
$
this
->
packageRepository
->
getExpiredForUpdate
(
)
;
foreach
(
$
packages
as
$
package
)
{
$
package
->
load
(
)
;
Yii
::
$
app
->
queue
->
push
(
Yii
::
createObject
(
PackageUpdateCommand
::
class
,
[
$
package
]
)
)
;
$
message
=
'Package %N'
.
$
package
->
getFullName
(
)
.
'%n'
;
$
message
.=
' was updated '
.
Yii
::
$
app
->
formatter
->
asRelativeTime
(
$
package
->
getUpdateTime
(
)
)
;
$
message
.=
". %GAdded to queue for update%n\n"
;
$
this
->
stdout
(
Console
::
renderColoredString
(
$
message
)
)
;
}
}


public function create(array $names): ClientInterface
    {
        // Create a new connection manager specific for this client
        $clientConnectionManager = new ConnectionManager();
        foreach ($names as $name) {
            $clientConnectionManager->registerExistingConnection($name, $this->connectionManager->getConnection($name));
        }

        $firstName = reset($names);
        $clientConnectionManager->setMaster($firstName);

        return new Client($clientConnectionManager, $this->eventDispatcher);
    }

Build an Client form multiple connection.

@param string $names

@return ClientInterface

Build an Client form multiple connection .


private function getUrl(array $config): string
    {
        if (null !== $config['dsn']) {
            return $config['dsn'];
        }

        return sprintf(
            '%s://%s:%s@%s:%d',
            $config['scheme'],
            $config['username'],
            $config['password'],
            $config['host'],
            $this->getPort($config)
        );
    }

private function getUrl ( array $ config ) : string { if ( null !== $ config [ 'dsn' ] ) { return $ config [ 'dsn' ] ; } return sprintf ( '%s://%s:%s@%s:%d' , $ config [ 'scheme' ] , $ config [ 'username' ] , $ config [ 'password' ] , $ config [ 'host' ] , $ this -> getPort ( $ config ) ) ; }

Get URL form config.

@param array $config

@return string


private function getPort(array $config)
    {
        if (isset($config['port'])) {
            return $config['port'];
        }

        return 'http' == $config['scheme'] ? HttpDriver::DEFAULT_HTTP_PORT : BoltDriver::DEFAULT_TCP_PORT;
    }

private function getPort ( array $ config ) { if ( isset ( $ config [ 'port' ] ) ) { return $ config [ 'port' ] ; } return 'http' == $ config [ 'scheme' ] ? HttpDriver :: DEFAULT_HTTP_PORT : BoltDriver :: DEFAULT_TCP_PORT ; }

Return the correct default port if not manually set.

@param array $config

@return int

Return the correct default port if not manually set .


private function validateEntityManagers(array &$config): bool
    {
        $dependenciesInstalled = class_exists(EntityManager::class);
        $entityManagersConfigured = !empty($config['entity_managers']);

        if ($dependenciesInstalled && !$entityManagersConfigured) {
            // Add default entity manager if none set.
            $config['entity_managers']['default'] = ['client' => 'default'];
        } elseif (!$dependenciesInstalled && $entityManagersConfigured) {
            throw new \LogicException(
                'You need to install "graphaware/neo4j-php-ogm" to be able to use the EntityManager'
            );
        }

        return $dependenciesInstalled;
    }

Make sure the EntityManager is installed if we have configured it.

@param array &$config

@return bool true if "graphaware/neo4j-php-ogm" is installed

@thorws \LogicException if EntityManagers os not installed but they are configured.

Make sure the EntityManager is installed if we have configured it .


private static function terminate_proc( $proc ) {
		$status = proc_get_status( $proc );

		$master_pid = $status['pid'];

		$output = `ps -o ppid,pid,command | grep $master_pid`;

		foreach ( explode( PHP_EOL, $output ) as $line ) {
			if ( preg_match( '/^\s*(\d+)\s+(\d+)/', $line, $matches ) ) {
				$parent = $matches[1];
				$child = $matches[2];

				if ( $parent == $master_pid ) {
					if ( ! posix_kill( (int) $child, 9 ) ) {
						throw new RuntimeException( posix_strerror( posix_get_last_error() ) );
					}
				}
			}
		}

		if ( ! posix_kill( (int) $master_pid, 9 ) ) {
			throw new RuntimeException( posix_strerror( posix_get_last_error() ) );
		}
	}

Terminate a process and any of its children.

Terminate a process and any of its children .


public function lock( $args, $assoc_args ) {
		if ( ! Book::isBook() ) {
			WP_CLI::warning( 'Not a book. Did you forget the --url parameter?' );
			return;
		}
		if ( CustomCss::isCustomCss() ) {
			WP_CLI::warning( "Deprecated! Can't lock a theme if it's Custom CSS" );
			return;
		}

		$lock = new Lock();
		if ( $lock->isLocked() ) {
			WP_CLI::warning( 'Theme already locked.' );
		} else {
			$data = $lock->lockTheme();
			if ( $data === false ) {
				WP_CLI::error( 'Theme could not be locked.' );
			} else {
				$this->updateThemeLockOption( true );
				WP_CLI::success( 'Theme was locked: ' . wp_json_encode( $data ) );
			}
		}
	}

Lock a book's theme.

## OPTIONS

--url=<url>
: The URL of the target book.

@when after_wp_load

@param array $args
@param array $assoc_args

@throws \WP_CLI\ExitException


public function unlock( $args, $assoc_args ) {
		if ( ! Book::isBook() ) {
			WP_CLI::warning( 'Not a book. Did you forget the --url parameter?' );
			return;
		}
		if ( CustomCss::isCustomCss() ) {
			WP_CLI::warning( "Deprecated! Can't unlock a theme if it's Custom CSS" );
			return;
		}

		$lock = new Lock();
		if ( ! $lock->isLocked() ) {
			WP_CLI::warning( 'Theme already unlocked.' );
		} else {
			$theme = $lock->unlockTheme();
			$this->updateThemeLockOption( false );
			WP_CLI::success( 'Theme was unlocked. Now using ' . $theme->get( 'Name' ) . ', version ' . $theme->get( 'Version' ) );
		}
	}

Unlock a book's theme.

## OPTIONS

--url=<url>
: The URL of the target book.

@when after_wp_load

@param array $args
@param array $assoc_args


public function clone( $args, $assoc_args ) {
		if ( count( $args ) < 2 ) {
			WP_CLI::error( 'Expects 3 parameters: <source> <dest> --user=<user> ' );
		}
		if ( ! get_current_user_id() ) {
			WP_CLI::error( 'Missing --user parameter (sets request to a specific WordPress user)' );
		}

		$success = false;
		try {
			$source = esc_url( $args[0] );

			$dest = Cloner::validateNewBookName( $args[1] );
			if ( is_wp_error( $dest ) ) {
				WP_CLI::error( '<dest> ' . $dest->get_error_message() );
			}

			WP_CLI::log( "Cloning {$source} into {$dest}" );

			\Pressbooks\Metadata\init_book_data_models();
			\Pressbooks\Api\init_book();
			$cloner = new Cloner( $source, $dest );
			$success = $cloner->cloneBook();

		} catch ( \Exception $e ) {
			// Do nothing, look at $_SESSION['pb_errors'] instead
		}

		if ( ! empty( $_SESSION['pb_errors'] ) ) {
			foreach ( $_SESSION['pb_errors'] as $error ) {
				$error = wp_strip_all_tags( $error, true );
				$error = html_entity_decode( $error );
				WP_CLI::warning( $error );
			}
		}
		if ( ! $success ) {
			WP_CLI::error( 'Cloning failed!' );
		} else {
			WP_CLI::success( 'Cloning succeeded!' );
		}
	}

Clone a book.

## OPTIONS

<source>
: URL

<destination>
: Book slug on the current network

--user=<user>
: sets request to a specific WordPress user

@when after_wp_load

@param array $args
@param array $assoc_args

@throws \WP_CLI\ExitException


private function buildParamValue($arrFilterUrl, $strParamName)
    {
        $arrParamValue = null;
        if (array_key_exists($strParamName, $arrFilterUrl) && !empty($arrFilterUrl[$strParamName])) {
            if (is_array($arrFilterUrl[$strParamName])) {
                $arrParamValue = $arrFilterUrl[$strParamName];
            } else {
                $arrParamValue = explode(',', $arrFilterUrl[$strParamName]);
            }
        }

        return $arrParamValue;
    }

private function buildParamValue ( $ arrFilterUrl , $ strParamName ) { $ arrParamValue = null ; if ( array_key_exists ( $ strParamName , $ arrFilterUrl ) && ! empty ( $ arrFilterUrl [ $ strParamName ] ) ) { if ( is_array ( $ arrFilterUrl [ $ strParamName ] ) ) { $ arrParamValue = $ arrFilterUrl [ $ strParamName ] ; } else { $ arrParamValue = explode ( ',' , $ arrFilterUrl [ $ strParamName ] ) ; } } return $ arrParamValue ; }

Build filter param values.

@param array  $arrFilterUrl Given filter url.
@param string $strParamName Name of filter param.

@return array|null


private function buildParameterFilterWidgets(
        $arrJumpTo,
        FrontendFilterOptions $objFrontendFilterOptions,
        $objAttribute,
        $strParamName,
        $arrOptions,
        $arrCount,
        $arrParamValue,
        $arrMyFilterUrl
    ) {
        return  array(
            $this->getParamName() => $this->prepareFrontendFilterWidget(
                array(
                    'label' => array(
                        ($this->get('label') ? $this->get('label') : $objAttribute->getName()),
                        'GET: ' . $strParamName
                    ),
                    'inputType' => 'tags',
                    'options' => $arrOptions,
                    'count' => $arrCount,
                    'showCount' => $objFrontendFilterOptions->isShowCountValues(),
                    'eval' => array(
                        'includeBlankOption' => (
                            $this->get('blankoption')
                            && !$objFrontendFilterOptions->isHideClearFilter()
                        ),
                        'blankOptionLabel'   => &$GLOBALS['TL_LANG']['metamodels_frontendfilter']['do_not_filter'],
                        'multiple'           => true,
                        'colname'            => $objAttribute->getColName(),
                        'urlparam'           => $strParamName,
                        'onlyused'           => $this->get('onlyused'),
                        'onlypossible'       => $this->get('onlypossible'),
                        'template'           => $this->get('template')
                    ),
                    // We need to implode again to have it transported correctly in the frontend filter.
                    'urlvalue' => !empty($arrParamValue) ? implode(',', $arrParamValue) : ''
                ),
                $arrMyFilterUrl,
                $arrJumpTo,
                $objFrontendFilterOptions
            )
        );
    }

Build parameter filter widgets.

@param array                 $arrJumpTo                The jumpTo page.
@param FrontendFilterOptions $objFrontendFilterOptions Frontendfilter options.
@param IAttribute            $objAttribute             MetaModel Attribute.
@param string                $strParamName             Param name.
@param array                 $arrOptions               Options.
@param array                 $arrCount                 Count configuration.
@param array|null            $arrParamValue            Parameter value.
@param array                 $arrMyFilterUrl           Filter url of the current filter.

@return array

@SuppressWarnings(PHPMD.Superglobals)
@SuppressWarnings(PHPMD.CamelCaseVariableName)


protected function sortedTables($reverse = false): array
    {
        $reflector = new Reflector();
        foreach ($this->tables as $table) {
            $reflector->addTable($table);
        }

        $sorted = $reflector->sortedTables();
        if ($reverse) {
            return array_reverse($sorted);
        }

        return $sorted;
    }

protected function sortedTables ( $ reverse = false ) : array { $ reflector = new Reflector ( ) ; foreach ( $ this -> tables as $ table ) { $ reflector -> addTable ( $ table ) ; } $ sorted = $ reflector -> sortedTables ( ) ; if ( $ reverse ) { return array_reverse ( $ sorted ) ; } return $ sorted ; }

Tables sorted in order of their dependencies.

@param bool $reverse
@return AbstractTable[]

Tables sorted in order of their dependencies .


public function isConfigured(): bool
    {
        foreach ($this->dbal->getDatabases() as $db) {
            if (!$db->hasTable($this->config->getTable())) {
                return false;
            }
        }

        return true;
    }

public function isConfigured ( ) : bool { foreach ( $ this -> dbal -> getDatabases ( ) as $ db ) { if ( ! $ db -> hasTable ( $ this -> config -> getTable ( ) ) ) { return false ; } } return true ; }

Check if all related databases are configures with migrations.

@return bool

Check if all related databases are configures with migrations .


public function configure()
    {
        if ($this->isConfigured()) {
            return;
        }

        foreach ($this->dbal->getDatabases() as $db) {
            $schema = $db->table($this->config->getTable())->getSchema();

            // Schema update will automatically sync all needed data
            $schema->primary('id');
            $schema->string('migration', 255)->nullable(false);
            $schema->datetime('time_executed')->datetime();
            $schema->index(['migration']);

            $schema->save();
        }
    }

Configure all related databases with migration table.

Configure all related databases with migration table .


public function getMigrations(): array
    {
        $result = [];
        foreach ($this->repository->getMigrations() as $migration) {
            //Populating migration state and execution time (if any)
            $result[] = $migration->withState($this->resolveState($migration));
        }

        return $result;
    }

Get every available migration with valid meta information.

@return MigrationInterface[]

Get every available migration with valid meta information .


public function run(CapsuleInterface $capsule = null): ?MigrationInterface
    {
        if (!$this->isConfigured()) {
            throw new MigrationException("Unable to run migration, Migrator not configured");
        }

        foreach ($this->getMigrations() as $migration) {
            if ($migration->getState()->getStatus() != State::STATUS_PENDING) {
                continue;
            }

            $capsule = $capsule ?? new Capsule($this->dbal->database($migration->getDatabase()));
            $capsule->getDatabase($migration->getDatabase())->transaction(function () use ($migration, $capsule) {
                $migration->withCapsule($capsule)->up();
            });

            $this->migrationTable($migration->getDatabase())->insertOne([
                'migration'     => $migration->getState()->getName(),
                'time_executed' => new \DateTime('now')
            ]);

            return $migration->withState($this->resolveState($migration));
        }

        return null;
    }

Execute one migration and return it's instance.

@param CapsuleInterface $capsule
@return null|MigrationInterface

@throws \Throwable

Execute one migration and return it s instance .


public function rollback(CapsuleInterface $capsule = null): ?MigrationInterface
    {
        if (!$this->isConfigured()) {
            throw new MigrationException("Unable to run migration, Migrator not configured");
        }

        /** @var MigrationInterface $migration */
        foreach (array_reverse($this->getMigrations()) as $migration) {
            if ($migration->getState()->getStatus() != State::STATUS_EXECUTED) {
                continue;
            }

            $capsule = $capsule ?? new Capsule($this->dbal->database($migration->getDatabase()));
            $capsule->getDatabase()->transaction(function () use ($migration, $capsule) {
                $migration->withCapsule($capsule)->down();
            });

            $this->migrationTable($migration->getDatabase())->delete([
                'migration' => $migration->getState()->getName()
            ])->run();

            return $migration->withState($this->resolveState($migration));
        }

        return null;
    }

Rollback last migration and return it's instance.

@param CapsuleInterface $capsule
@return null|MigrationInterface

@throws \Throwable

Rollback last migration and return it s instance .


protected function resolveState(MigrationInterface $migration): State
    {
        $db = $this->dbal->database($migration->getDatabase());

        //Fetch migration information from database
        $data = $this->migrationTable($migration->getDatabase())
                     ->select('id', 'time_executed')
                     ->where(['migration' => $migration->getState()->getName()])
                     ->run()->fetch();

        if (empty($data['time_executed'])) {
            return $migration->getState()->withStatus(State::STATUS_PENDING);
        }

        return $migration->getState()->withStatus(
            State::STATUS_EXECUTED,
            new \DateTime($data['time_executed'], $db->getDriver()->getTimezone())
        );
    }

Clarify migration state with valid status and execution time

@param MigrationInterface $migration
@return State


protected function migrationTable(string $database = null): Table
    {
        return $this->dbal->database($database)->table($this->config->getTable());
    }

protected function migrationTable ( string $ database = null ) : Table { return $ this -> dbal -> database ( $ database ) -> table ( $ this -> config -> getTable ( ) ) ; }

Migration table, all migration information will be stored in it.

@param string|null $database
@return Table

Migration table all migration information will be stored in it .


protected function render(Source $source, string $format, ...$values)
    {
        $serializer = $this->getSerializer();

        $rendered = [];
        foreach ($values as $value) {
            if ($value instanceof AbstractTable) {
                $rendered[] = $serializer->serialize(
                    substr($value->getName(), strlen($value->getPrefix()))
                );
                continue;
            }

            if ($value instanceof AbstractColumn) {
                $rendered[] = $this->columnOptions($serializer, $value);
                continue;
            }

            if ($value instanceof AbstractIndex) {
                $rendered[] = $this->indexOptions($serializer, $value);
                continue;
            }

            if ($value instanceof AbstractForeignKey) {
                $rendered[] = $this->foreignKeyOptions($serializer, $value);
                continue;
            }

            // numeric array
            if (is_array($value) && count($value) > 0 && is_numeric(array_keys($value)[0])) {
                $rendered[] = '["' . join('", "', $value) . '"]';
                continue;
            }

            $rendered[] = $serializer->serialize($value);
        }

        $lines = sprintf($format, ...$rendered);
        foreach (explode("\n", $lines) as $line) {
            $source->addLine($line);
        }
    }

protected
function
render
(
Source
$
source
,
string
$
format
,
...
$
values
)
{
$
serializer
=
$
this
->
getSerializer
(
)
;
$
rendered
=
[
]
;
foreach
(
$
values
as
$
value
)
{
if
(
$
value
instanceof
AbstractTable
)
{
$
rendered
[
]
=
$
serializer
->
serialize
(
substr
(
$
value
->
getName
(
)
,
strlen
(
$
value
->
getPrefix
(
)
)
)
)
;
continue
;
}
if
(
$
value
instanceof
AbstractColumn
)
{
$
rendered
[
]
=
$
this
->
columnOptions
(
$
serializer
,
$
value
)
;
continue
;
}
if
(
$
value
instanceof
AbstractIndex
)
{
$
rendered
[
]
=
$
this
->
indexOptions
(
$
serializer
,
$
value
)
;
continue
;
}
if
(
$
value
instanceof
AbstractForeignKey
)
{
$
rendered
[
]
=
$
this
->
foreignKeyOptions
(
$
serializer
,
$
value
)
;
continue
;
}
// numeric array
if
(
is_array
(
$
value
)
&&
count
(
$
value
)
>
0
&&
is_numeric
(
array_keys
(
$
value
)
[
0
]
)
)
{
$
rendered
[
]
=
'["'
.
join
(
'", "'
,
$
value
)
.
'"]'
;
continue
;
}
$
rendered
[
]
=
$
serializer
->
serialize
(
$
value
)
;
}
$
lines
=
sprintf
(
$
format
,
...
$
rendered
)
;
foreach
(
explode
(
"\n"
,
$
lines
)
as
$
line
)
{
$
source
->
addLine
(
$
line
)
;
}
}

Render values and options into source.

@param Source $source
@param string $format
@param array  ...$values


private function mountIndents(string $serialized): string
    {
        $lines = explode("\n", $serialized);
        foreach ($lines as &$line) {
            $line = "    " . $line;
            unset($line);
        }

        return ltrim(join("\n", $lines));
    }

private
function
mountIndents
(
string
$
serialized
)
:
string
{
$
lines
=
explode
(
"\n"
,
$
serialized
)
;
foreach
(
$
lines
as
&
$
line
)
{
$
line
=
"    "
.
$
line
;
unset
(
$
line
)
;
}
return
ltrim
(
join
(
"\n"
,
$
lines
)
)
;
}

Mount indents for column and index options.

@param $serialized
@return string

Mount indents for column and index options .


public function setPrimaryKeys(array $keys): self
    {
        return $this->addOperation(
            new Operation\Table\PrimaryKeys($this->table, $keys)
        );
    }

public function setPrimaryKeys ( array $ keys ) : self { return $ this -> addOperation ( new Operation \ Table \ PrimaryKeys ( $ this -> table , $ keys ) ) ; }

Set table primary keys index. Attention, you can only call it when table being created.

@param array $keys
@return TableBlueprint

Set table primary keys index . Attention you can only call it when table being created .


public function create()
    {
        $this->addOperation(
            new Operation\Table\Create($this->table)
        );

        $this->execute();
    }

public function create ( ) { $ this -> addOperation ( new Operation \ Table \ Create ( $ this -> table ) ) ; $ this -> execute ( ) ; }

Create table schema. Must be last operation in the sequence.

Create table schema . Must be last operation in the sequence .


public function update()
    {
        $this->addOperation(
            new Operation\Table\Update($this->table)
        );

        $this->execute();
    }

public function update ( ) { $ this -> addOperation ( new Operation \ Table \ Update ( $ this -> table ) ) ; $ this -> execute ( ) ; }

Update table schema. Must be last operation in the sequence.

Update table schema . Must be last operation in the sequence .


public function drop()
    {
        $this->addOperation(
            new Operation\Table\Drop($this->table)
        );

        $this->execute();
    }

public function drop ( ) { $ this -> addOperation ( new Operation \ Table \ Drop ( $ this -> table ) ) ; $ this -> execute ( ) ; }

Drop table. Must be last operation in the sequence.

Drop table . Must be last operation in the sequence .


public function rename(string $newName)
    {
        $this->addOperation(
            new Operation\Table\Rename($this->table, $newName)
        );

        $this->execute();
    }

public function rename ( string $ newName ) { $ this -> addOperation ( new Operation \ Table \ Rename ( $ this -> table , $ newName ) ) ; $ this -> execute ( ) ; }

Rename table. Must be last operation in the sequence.

@param string $newName

Rename table . Must be last operation in the sequence .


private function execute()
    {
        if ($this->executed) {
            throw new BlueprintException("Only one create/update/rename/drop is allowed per blueprint.");
        }

        $this->capsule->execute($this->operations);
        $this->executed = true;
    }


private function getFiles(): \Generator
    {
        foreach ($this->files->getFiles($this->config->getDirectory(), '*.php') as $filename) {
            $reflection = new ReflectionFile($filename);
            $definition = explode('_', basename($filename));

            if (count($definition) < 3) {
                throw new RepositoryException("Invalid migration filename '{$filename}'");
            }

            yield [
                'filename' => $filename,
                'class'    => $reflection->getClasses()[0],
                'created'  => \DateTime::createFromFormat(
                    self::TIMESTAMP_FORMAT,
                    $definition[0]
                ),
                'chunk'    => $definition[1],
                'name'     => str_replace(
                    '.php',
                    '',
                    join('_', array_slice($definition, 2))
                )
            ];
        }
    }

Internal method to fetch all migration filenames.

Internal method to fetch all migration filenames .


private function createFilename(string $name): string
    {
        $name = Inflector::tableize($name);

        $filename = sprintf(self::FILENAME_FORMAT,
            date(self::TIMESTAMP_FORMAT),
            $this->chunkID++,
            $name
        );

        return $this->files->normalizePath(
            $this->config->getDirectory() . FilesInterface::SEPARATOR . $filename
        );
    }

private function createFilename ( string $ name ) : string { $ name = Inflector :: tableize ( $ name ) ; $ filename = sprintf ( self :: FILENAME_FORMAT , date ( self :: TIMESTAMP_FORMAT ) , $ this -> chunkID ++ , $ name ) ; return $ this -> files -> normalizePath ( $ this -> config -> getDirectory ( ) . FilesInterface :: SEPARATOR . $ filename ) ; }

Request new migration filename based on user input and current timestamp.

@param string $name
@return string

Request new migration filename based on user input and current timestamp .


public function boot()
    {
        $bootstrapPath = $this->basePath() . '/bootstrap/app.php';

        $this->assertBootstrapFileExists($bootstrapPath);

        $app = require $bootstrapPath;

        $app->loadEnvironmentFrom($this->environmentFile());

        $app->make('Illuminate\Contracts\Console\Kernel')->bootstrap();

        $app->make('Illuminate\Http\Request')->capture();

        return $app;
    }

public function boot ( ) { $ bootstrapPath = $ this -> basePath ( ) . '/bootstrap/app.php' ; $ this -> assertBootstrapFileExists ( $ bootstrapPath ) ; $ app = require $ bootstrapPath ; $ app -> loadEnvironmentFrom ( $ this -> environmentFile ( ) ) ; $ app -> make ( 'Illuminate\Contracts\Console\Kernel' ) -> bootstrap ( ) ; $ app -> make ( 'Illuminate\Http\Request' ) -> capture ( ) ; return $ app ; }


private function loadLaravel(ContainerBuilder $container, array $config)
    {
        $laravel = new LaravelBooter($container->getParameter('paths.base'), $config['env_path']);

        $container->set('laravel.app', $app = $laravel->boot());

        return $app;
    }

private function loadLaravel ( ContainerBuilder $ container , array $ config ) { $ laravel = new LaravelBooter ( $ container -> getParameter ( 'paths.base' ) , $ config [ 'env_path' ] ) ; $ container -> set ( 'laravel.app' , $ app = $ laravel -> boot ( ) ) ; return $ app ; }

Boot up Laravel.

@param ContainerBuilder $container
@param array            $config
@return mixed


private function loadInitializer(ContainerBuilder $container, $app)
    {
        $definition = new Definition('Laracasts\Behat\Context\KernelAwareInitializer', [$app]);

        $definition->addTag(EventDispatcherExtension::SUBSCRIBER_TAG, ['priority' => 0]);
        $definition->addTag(ContextExtension::INITIALIZER_TAG, ['priority' => 0]);

        $container->setDefinition('laravel.initializer', $definition);
    }

Load the initializer.

@param ContainerBuilder    $container
@param HttpKernelInterface $app


private function loadLaravelArgumentResolver(ContainerBuilder $container, $app)
    {
        $definition = new Definition(LaravelArgumentResolver::class, [
            new Reference('laravel.app')
        ]);
        $definition->addTag(ContextExtension::ARGUMENT_RESOLVER_TAG, ['priority' => 0]);
        $container->setDefinition('laravel.context.argument.service_resolver', $definition);
    }

Load argument resolver

@param  ContainerBuilder $container
@param  Application $app


protected function applyMailTrapConfiguration($inboxId = null)
    {
        if (is_null($config = Config::get('services.mailtrap'))) {
            throw new Exception(
                'Set "secret" and "default_inbox" keys for "mailtrap" in "config/services.php."'
            );
        }

        $this->mailTrapInboxId = $inboxId ?: $config['default_inbox'];
        $this->mailTrapApiKey = $config['secret'];
    }

Get the configuration for MailTrap.

@param integer|null $inboxId
@throws Exception


protected function fetchInbox($inboxId = null)
    {
        if ( ! $this->alreadyConfigured()) {
            $this->applyMailTrapConfiguration($inboxId);
        }

        $body = $this->requestClient()
            ->get($this->getMailTrapMessagesUrl())
            ->getBody();

        return $this->parseJson($body);
    }

protected function fetchInbox ( $ inboxId = null ) { if ( ! $ this -> alreadyConfigured ( ) ) { $ this -> applyMailTrapConfiguration ( $ inboxId ) ; } $ body = $ this -> requestClient ( ) -> get ( $ this -> getMailTrapMessagesUrl ( ) ) -> getBody ( ) ; return $ this -> parseJson ( $ body ) ; }

Fetch a MailTrap inbox.

@param  integer|null $inboxId
@return mixed
@throws RuntimeException


protected function requestClient()
    {
        if ( ! $this->client) {
            $this->client = new Client([
                'base_uri' => 'https://mailtrap.io',
                'headers' => ['Api-Token' => $this->mailTrapApiKey]
            ]);
        }

        return $this->client;
    }

protected function requestClient ( ) { if ( ! $ this -> client ) { $ this -> client = new Client ( [ 'base_uri' => 'https://mailtrap.io' , 'headers' => [ 'Api-Token' => $ this -> mailTrapApiKey ] ] ) ; } return $ this -> client ; }

Request a new Guzzle client.

@return Client


public function rebootKernel()
    {
        if ($this->context instanceof KernelAwareContext)
        {
            $this->kernel->flush();

            $laravel = new LaravelBooter($this->kernel->basePath(), $this->kernel->environmentFile());

            $this->context->getSession('laravel')->getDriver()->reboot($this->kernel = $laravel->boot());

            $this->setAppOnContext();
        }
    }

public function rebootKernel ( ) { if ( $ this -> context instanceof KernelAwareContext ) { $ this -> kernel -> flush ( ) ; $ laravel = new LaravelBooter ( $ this -> kernel -> basePath ( ) , $ this -> kernel -> environmentFile ( ) ) ; $ this -> context -> getSession ( 'laravel' ) -> getDriver ( ) -> reboot ( $ this -> kernel = $ laravel -> boot ( ) ) ; $ this -> setAppOnContext ( ) ; } }


public function resolveArguments(ReflectionClass $classReflection, array $arguments)
    {
        $resolvedArguments = [];

        foreach ($arguments as $key => $argument) {
            $resolvedArguments[$key] = $this->resolveArgument($argument);
        }

        return $resolvedArguments;
    }

public function resolveArguments ( ReflectionClass $ classReflection , array $ arguments ) { $ resolvedArguments = [ ] ; foreach ( $ arguments as $ key => $ argument ) { $ resolvedArguments [ $ key ] = $ this -> resolveArgument ( $ argument ) ; } return $ resolvedArguments ; }

Resolves context constructor arguments.

@param ReflectionClass $classReflection
@param mixed[]         $arguments

@return mixed[]

Resolves context constructor arguments .


public function stream_open($path, $mode, $options, &$opened_path)
    {
        if (!isset(self::$uris[$path])) {
            return false;
        }

        $this->stream = self::$uris[$path];
        $this->mode = $mode;

        $this->stream->rewind();

        return true;
    }

public function stream_open ( $ path , $ mode , $ options , & $ opened_path ) { if ( ! isset ( self :: $ uris [ $ path ] ) ) { return false ; } $ this -> stream = self :: $ uris [ $ path ] ; $ this -> mode = $ mode ; $ this -> stream -> rewind ( ) ; return true ; }

Open pre-mocked StreamInterface by it's unique uri.

@param string  $path
@param int     $mode
@param int     $options
@param string &$opened_path
@return bool

Open pre - mocked StreamInterface by it s unique uri .


public function url_stat($path, $flags)
    {
        if (!isset(self::$uris[$path])) {
            return null;
        }

        return $this->getStreamStats(self::$uris[$path]);
    }

public function url_stat ( $ path , $ flags ) { if ( ! isset ( self :: $ uris [ $ path ] ) ) { return null ; } return $ this -> getStreamStats ( self :: $ uris [ $ path ] ) ; }

Get stats based on wrapped StreamInterface by it's mocked uri.

@see stat()
@param string $path
@param int    $flags
@return array|null

Get stats based on wrapped StreamInterface by it s mocked uri .


private function getStreamStats(StreamInterface $stream)
    {
        $mode = $this->mode;
        if (empty($mode)) {
            if ($stream->isReadable()) {
                $mode = 'r';
            }

            if ($stream->isWritable()) {
                $mode = !empty($mode) ? 'r+' : 'w';
            }
        }

        return [
            'dev'     => 0,
            'ino'     => 0,
            'mode'    => self::$modes[$mode],
            'nlink'   => 0,
            'uid'     => 0,
            'gid'     => 0,
            'rdev'    => 0,
            'size'    => (string)$stream->getSize(),
            'atime'   => 0,
            'mtime'   => 0,
            'ctime'   => 0,
            'blksize' => 0,
            'blocks'  => 0
        ];
    }

private function getStreamStats ( StreamInterface $ stream ) { $ mode = $ this -> mode ; if ( empty ( $ mode ) ) { if ( $ stream -> isReadable ( ) ) { $ mode = 'r' ; } if ( $ stream -> isWritable ( ) ) { $ mode = ! empty ( $ mode ) ? 'r+' : 'w' ; } } return [ 'dev' => 0 , 'ino' => 0 , 'mode' => self :: $ modes [ $ mode ] , 'nlink' => 0 , 'uid' => 0 , 'gid' => 0 , 'rdev' => 0 , 'size' => ( string ) $ stream -> getSize ( ) , 'atime' => 0 , 'mtime' => 0 , 'ctime' => 0 , 'blksize' => 0 , 'blocks' => 0 ] ; }

Helper method used to correctly resolve StreamInterface stats.

@param StreamInterface $stream
@return array

Helper method used to correctly resolve StreamInterface stats .


public static function has($file)
    {
        if ($file instanceof StreamInterface) {
            $file = 'spiral://' . spl_object_hash($file);
        }

        return isset(self::$uris[$file]);
    }

public static function has ( $ file ) { if ( $ file instanceof StreamInterface ) { $ file = 'spiral://' . spl_object_hash ( $ file ) ; } return isset ( self :: $ uris [ $ file ] ) ; }

Check if given uri or stream has been allocated.

@param string|StreamInterface $file
@return bool

Check if given uri or stream has been allocated .


public static function getFilename(StreamInterface $stream)
    {
        self::register();

        $uri = 'spiral://' . spl_object_hash($stream);
        self::$uris[$uri] = $stream;

        return $uri;
    }

public static function getFilename ( StreamInterface $ stream ) { self :: register ( ) ; $ uri = 'spiral://' . spl_object_hash ( $ stream ) ; self :: $ uris [ $ uri ] = $ stream ; return $ uri ; }

Register StreamInterface and get unique url for it.

@param StreamInterface $stream
@return string

Register StreamInterface and get unique url for it .


public static function release($file)
    {
        if ($file instanceof StreamInterface) {
            $file = 'spiral://' . spl_object_hash($file);
        }

        unset(self::$uris[$file]);
    }

public static function release ( $ file ) { if ( $ file instanceof StreamInterface ) { $ file = 'spiral://' . spl_object_hash ( $ file ) ; } unset ( self :: $ uris [ $ file ] ) ; }

Free uri dedicated to specified StreamInterface. Method is useful for long living
applications. You must close resource by yourself!

@param string|StreamInterface $file String uri or StreamInterface.

Free uri dedicated to specified StreamInterface . Method is useful for long living applications . You must close resource by yourself!


public function handle($command): CancellablePromiseInterface
    {
        return futurePromise($this->loop, $command)->then(function ($command) {
            return resolve($this->commandBus->handle($command));
        });
    }

public function handle ( $ command ) : CancellablePromiseInterface { return futurePromise ( $ this -> loop , $ command ) -> then ( function ( $ command ) { return resolve ( $ this -> commandBus -> handle ( $ command ) ) ; } ) ; }

Executes the given command and optionally returns a value.

@param object $command

@return CancellablePromiseInterface

Executes the given command and optionally returns a value .


public function emptyNodeExpansionWorked()
    {
        if ($this->properties['nodeType'] == \XMLReader::ELEMENT &&
            $this->properties['isEmptyElement'] == true) {
            $this->properties['nodeType'] = \XMLReader::END_ELEMENT;
            $this->properties['isEmptyElement'] = false;
            return true;
        }
        return false;
    }

public function emptyNodeExpansionWorked ( ) { if ( $ this -> properties [ 'nodeType' ] == \ XMLReader :: ELEMENT && $ this -> properties [ 'isEmptyElement' ] == true ) { $ this -> properties [ 'nodeType' ] = \ XMLReader :: END_ELEMENT ; $ this -> properties [ 'isEmptyElement' ] = false ; return true ; } return false ; }

Try to expand the current node if it's an empty one
and return whether the expansion worked or not.

\retval bool
\c true if this node was an empty one and it
was successfully expanded, \c false otherwise.

Try to expand the current node if it s an empty one and return whether the expansion worked or not .


public function expose($other, $prefix = '')
    {
        if (!is_string($other) && !is_object($other)) {
            throw new \InvalidArgumentException('Invalid adoption');
        }

        if (!is_string($prefix)) {
            throw new \InvalidArgumentException('Invalid prefix');
        }

        $prefix = rtrim($prefix, '.');
        if ($prefix !== '') {
            $prefix .= '.';
        }

        if (is_object($other)) {
            // An object was passed.
            $class = get_class($other);
            foreach (get_class_methods($class) as $method) {
                // Only adopt public methods of the object,
                // excluding the constructor and static methods.
                // To also register static methods, call this method
                // a second time with get_class($other).
                $reflector = new \ReflectionMethod($class, $method);
                if ($reflector->isPublic() && !$reflector->isConstructor() &&
                    !$reflector->isStatic()) {
                    $this[$prefix . $method] = array($other, $method);
                }
            }
        } else {
            // A class was passed.
            foreach (get_class_methods($other) as $method) {
                // Only adopt methods which are both public and static.
                $reflector = new \ReflectionMethod($other, $method);
                if ($reflector->isPublic() && $reflector->isStatic()) {
                    $this[$prefix . $method] = array($other, $method);
                }
            }
        }
    }

Expose the public methods of a class or object,
with an optional prefix.

\param mixed $other
Class or object to expose.
For classes, only public static methods are exposed.
For objects, public non-static methods are exposed,
except for the constructor.

\param string $prefix
Prefix under which the class/object's methods
will be exposed. Defaults to the empty string
(ie. the methods are exposed without any prefix).

\return
This method does not return any value.

\note
To expose all public methods of an object (both
static and non-static), call this method twice:
- once with the actual object
- and a second time with get_class($object)

Expose the public methods of a class or object with an optional prefix .


public function handle($URI = null)
    {
        if ($URI === null) {
            $URI = 'php://input';
        }

        try {
            $request    = $this->XRLDecoder->decodeRequest($URI);
            $procedure  = $request->getProcedure();
            // Necessary to keep references.
            $params     = $request->getParams();

            $result     = $this->call($procedure, $params);
            $response   = $this->XRLEncoder->encodeResponse($result);
        } catch (\Exception $result) {
            $response   = $this->XRLEncoder->encodeError($result);
        }

        return new \fpoirotte\XRL\Response($response);
    }

public
function
handle
(
$
URI
=
)
{
if
(
$
URI
===
)
{
$
URI
=
'php://input'
;
}
try
{
$
request
=
$
this
->
XRLDecoder
->
decodeRequest
(
$
URI
)
;
$
procedure
=
$
request
->
getProcedure
(
)
;
// Necessary to keep references.
$
params
=
$
request
->
getParams
(
)
;
$
result
=
$
this
->
call
(
$
procedure
,
$
params
)
;
$
response
=
$
this
->
XRLEncoder
->
encodeResponse
(
$
result
)
;
}
catch
(
\
Exception
$
result
)
{
$
response
=
$
this
->
XRLEncoder
->
encodeError
(
$
result
)
;
}
return
new
\
fpoirotte
\
XRL
\
Response
(
$
response
)
;
}

Handle an XML-RPC request and return a response for it.

\param string $URI
(optional) URI to the XML-RPC request to process,
If omitted, this method will try to retrieve the request
directly from the data POST'ed to this script.

\retval fpoirotte::XRL::ResponseInterface
The response for that request. This response
may indicate either success or failure of the
Remote Procedure Call.

\note
Use the "data://" wrapper to pass the serialized
request as raw data.

\see
See http://php.net/wrappers.data.php for information
on how to use the "data://" wrapper.

Handle an XML - RPC request and return a response for it .


public function call($procedure, array $params)
    {
        if (!is_string($procedure)) {
            throw new \BadFunctionCallException('Expected a string');
        }

        if (!isset($this->XRLFunctions[$procedure])) {
            throw new \fpoirotte\XRL\Faults\MethodNotFoundException();
        }

        $callable = $this->XRLFunctions[$procedure];
        return $callable(...$params);
    }

public
function
call
(
$
procedure
,
array
$
params
)
{
if
(
!
is_string
(
$
procedure
)
)
{
throw
new
\
BadFunctionCallException
(
'Expected a string'
)
;
}
if
(
!
isset
(
$
this
->
XRLFunctions
[
$
procedure
]
)
)
{
throw
new
\
fpoirotte
\
XRL
\
Faults
\
MethodNotFoundException
(
)
;
}
$
callable
=
$
this
->
XRLFunctions
[
$
procedure
]
;
return
$
callable
(
...
$
params
)
;
}

Call an XML-RPC procedure.

\param string $procedure
Name of the procedure to call.

\param array $params
Parameters for that procedure.

\retval mixed
The procedure's return value.


protected function renderInput()
    {
        if ($this->hasModel()) {
            $content = Html::activeCheckboxList(
                $this->model,
                $this->attribute,
                $this->items,
                $this->options
            );
        } else {
            $content = Html::checkboxList(
                $this->name,
                $this->value,
                $this->items,
                $this->options
            );
        }

        return Html::tag(
            'div',
            $content,
            [
                'id' => $this->widgetId.'-checkbox',
                'class' => 'checkbox_button_group'.'_checkbox',
            ]
        );
    }

protected function renderInput ( ) { if ( $ this -> hasModel ( ) ) { $ content = Html :: activeCheckboxList ( $ this -> model , $ this -> attribute , $ this -> items , $ this -> options ) ; } else { $ content = Html :: checkboxList ( $ this -> name , $ this -> value , $ this -> items , $ this -> options ) ; } return Html :: tag ( 'div' , $ content , [ 'id' => $ this -> widgetId . '-checkbox' , 'class' => 'checkbox_button_group' . '_checkbox' , ] ) ; }


public static function enable(\fpoirotte\XRL\Server $server, array $whitelist = null)
    {
        $wrapper = new static($server, $whitelist);
        $server->expose($wrapper, 'system');
        return $server;
    }

public static function enable ( \ fpoirotte \ XRL \ Server $ server , array $ whitelist = null ) { $ wrapper = new static ( $ server , $ whitelist ) ; $ server -> expose ( $ wrapper , 'system' ) ; return $ server ; }

Turn a regular XML-RPC server into one
that supports various XML-RPC capabilities.

\param fpoirotte::XRL::Server $server
An XML-RPC to upgrade.

\param array $whitelist
(optional) Whitelist of methods that can
be announced by the newly upgraded server.
Pass an empty array to disable announces.
By default, all methods are announced.

\retval fpoirotte::XRL::Server
The upgraded server.

Turn a regular XML - RPC server into one that supports various XML - RPC capabilities .


protected static function extractTypes($doc)
    {
        $doc    = trim(substr($doc, 3, -2), " \t\r\n*");
        $doc    = str_replace(array("\r\n", "\r"), "\n", $doc);
        $lines  = explode("\n", $doc . "\n");

        $tag    = null;
        $tags   = array(
            'params'    => array(),
            'retval'    => 'null',
        );
        $buffer = '';

        foreach ($lines as $line) {
            $line = trim($line, " \r\n\t*");

            if ($tag !== null && $line === '') {
                switch ($tag) {
                    case 'param':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $buffer = ltrim(substr($buffer, strcspn($buffer, " \r\n\t")));
                        if (strncmp($buffer, '$', 1)) {
                            break;
                        }

                        $name = (string) substr($buffer, 1, strcspn($buffer, " \r\n\t") - 1);
                        $tags['params'][$name] = $type;
                        break;

                    case 'retval':
                        $type = (string) substr($buffer, 0, strcspn($buffer, " \r\n\t"));
                        $tags['retval'] = $type;
                        break;
                }

                $tag    = null;
                $buffer = '';
                continue;
            }

            if ($tag === null) {
                // \command or @command.
                if (!strncmp($line, '\\', 1) || !strncmp($line, '@', 1)) {
                    $tag    = (string) substr($line, 1, strcspn($line, " \r\n\t") - 1);
                    $buffer = ltrim(substr($line, strcspn($line, " \r\n\t")));
                }
            } else {
                // Continuation of previous paragraph.
                $buffer .= "\n$line";
            }
        }
        return $tags;
    }

protected
static
function
extractTypes
(
$
doc
)
{
$
doc
=
trim
(
substr
(
$
doc
,
3
,
2
)
,
" \t\r\n*"
)
;
$
doc
=
str_replace
(
array
(
"\r\n"
,
"\r"
)
,
"\n"
,
$
doc
)
;
$
lines
=
explode
(
"\n"
,
$
doc
.
"\n"
)
;
$
tag
=
;
$
tags
=
array
(
'params'
=>
array
(
)
,
'retval'
=>
'null'
,
)
;
$
buffer
=
''
;
foreach
(
$
lines
as
$
line
)
{
$
line
=
trim
(
$
line
,
" \r\n\t*"
)
;
if
(
$
tag
!==
&&
$
line
===
''
)
{
switch
(
$
tag
)
{
case
'param'
:
$
type
=
(
string
)
substr
(
$
buffer
,
0
,
strcspn
(
$
buffer
,
" \r\n\t"
)
)
;
$
buffer
=
ltrim
(
substr
(
$
buffer
,
strcspn
(
$
buffer
,
" \r\n\t"
)
)
)
;
if
(
strncmp
(
$
buffer
,
'$'
,
1
)
)
{
break
;
}
$
name
=
(
string
)
substr
(
$
buffer
,
1
,
strcspn
(
$
buffer
,
" \r\n\t"
)
1
)
;
$
tags
[
'params'
]
[
$
name
]
=
$
type
;
break
;
case
'retval'
:
$
type
=
(
string
)
substr
(
$
buffer
,
0
,
strcspn
(
$
buffer
,
" \r\n\t"
)
)
;
$
tags
[
'retval'
]
=
$
type
;
break
;
}
$
tag
=
;
$
buffer
=
''
;
continue
;
}
if
(
$
tag
===
)
{
// \command or @command.
if
(
!
strncmp
(
$
line
,
'\\'
,
1
)
||
!
strncmp
(
$
line
,
'@'
,
1
)
)
{
$
tag
=
(
string
)
substr
(
$
line
,
1
,
strcspn
(
$
line
,
" \r\n\t"
)
1
)
;
$
buffer
=
ltrim
(
substr
(
$
line
,
strcspn
(
$
line
,
" \r\n\t"
)
)
)
;
}
}
else
{
// Continuation of previous paragraph.
$
buffer
.=
"\n$line"
;
}
}
return
$
tags
;
}

Extract parameter and return type information
from a documentation comment.

\param string $doc
Documentation comment the types
will be extracted from.

\retval array
Array with type information.
The "retval" key contains information about the return type,
while the array in the "params" key contains information
about each parameter's type (indexed by its name).

Extract parameter and return type information from a documentation comment .


public function listMethods()
    {
        $methods = array_keys($this->server->getIterator()->getArrayCopy());
        if ($this->whitelist !== null) {
            $methods = array_values(array_intersect($methods, $this->whitelist));
        }
        return $methods;
    }

public function listMethods ( ) { $ methods = array_keys ( $ this -> server -> getIterator ( ) -> getArrayCopy ( ) ) ; if ( $ this -> whitelist !== null ) { $ methods = array_values ( array_intersect ( $ methods , $ this -> whitelist ) ) ; } return $ methods ; }

List the methods supported by the server.

\retval array
Array with the names of available methods.

List the methods supported by the server .


public function methodSignature($method)
    {
        if (!is_string($method) || !isset($this->server[$method])) {
            throw new \InvalidArgumentException('Invalid method');
        }

        $reflector  = $this->server[$method]->getReflector();
        $doc        = $reflector->getDocComment();
        if ($doc === false) {
            return 'undef';
        }

        $tags       = static::extractTypes($doc);
        $returnType = static::adaptType($tags['retval']);
        if ($returnType === null) {
            return 'undef';
        }

        $params     = array();
        foreach ($reflector->getParameters() as $param) {
            if (!isset($tags['params'][$param->getName()])) {
                return 'undef';
            }
            $type       = static::adaptType($tags['params'][$param->getName()]);
            if ($type === null) {
                return 'undef';
            }
            $params[]   = $type;
        }

        return array(array_merge(array($returnType), $params));
    }

public
function
methodSignature
(
$
method
)
{
if
(
!
is_string
(
$
method
)
||
!
isset
(
$
this
->
server
[
$
method
]
)
)
{
throw
new
\
InvalidArgumentException
(
'Invalid method'
)
;
}
$
reflector
=
$
this
->
server
[
$
method
]
->
getReflector
(
)
;
$
doc
=
$
reflector
->
getDocComment
(
)
;
if
(
$
doc
===
false
)
{
return
'undef'
;
}
$
tags
=
static
::
extractTypes
(
$
doc
)
;
$
returnType
=
static
::
adaptType
(
$
tags
[
'retval'
]
)
;
if
(
$
returnType
===
)
{
return
'undef'
;
}
$
params
=
array
(
)
;
foreach
(
$
reflector
->
getParameters
(
)
as
$
param
)
{
if
(
!
isset
(
$
tags
[
'params'
]
[
$
param
->
getName
(
)
]
)
)
{
return
'undef'
;
}
$
type
=
static
::
adaptType
(
$
tags
[
'params'
]
[
$
param
->
getName
(
)
]
)
;
if
(
$
type
===
)
{
return
'undef'
;
}
$
params
[
]
=
$
type
;
}
return
array
(
array_merge
(
array
(
$
returnType
)
,
$
params
)
)
;
}

Return possible signatures for a method.

\param string $method
Name of the method.

\retval array
An array containing:
- The return type of the method as its first value
- The types for the method's parameters in the following values

Return possible signatures for a method .


public function methodHelp($method)
    {
        if (!is_string($method) || !isset($this->server[$method])) {
            throw new \InvalidArgumentException('Invalid method');
        }

        $reflector  = $this->server[$method]->getReflector();
        $doc        = $reflector->getDocComment();
        if ($doc === false) {
            return '';
        }

        // Remove comment delimiters.
        $doc    = substr($doc, 2, -2);

        // Normalize line endings.
        $doc    = str_replace(array("\r\n", "\r"), "\n", $doc);

        // Trim leading/trailing whitespace and '*' for every line.
        $help   = array_map(
            function ($l) {
                return trim(trim($l), '*');
            },
            explode("\n", $doc)
        );

        // Count number of empty columns on non-empty lines
        // before the actual start of the text.
        $cols = min(
            array_map(
                function ($l) {
                    return strspn($l, " \t");
                },
                array_filter($help, 'strlen')
            )
        );

        // Remove those columns from the result.
        $help = array_map(
            function ($l) use ($cols) {
                return (string) substr($l, $cols);
            },
            $help
        );

        // Produce the final output.
        return implode("\n", $help);
    }

Get help about a procedure.

\param string $method
Name of the procedure.

\retval string
Human readable help message for the given procedure.


public function multicall(array $requests)
    {
        $responses = array();
        foreach ($requests as $request) {
            try {
                if (!is_array($request)) {
                    throw new \BadFunctionCallException('Expected struct');
                }
                if (!isset($request['methodName'])) {
                    throw new \BadFunctionCallException('Missing methodName');
                }
                if (!isset($request['params'])) {
                    throw new \BadFunctionCallException('Missing params');
                }
                if (!is_array($request['params'])) {
                    throw new \BadFunctionCallException('Invalid params');
                }
                if ($request['methodName'] === 'system.multicall') {
                    throw new \BadFunctionCallException('Recursive call');
                }

                $result = $this->server->call($request['methodName'], $request['params']);
                // Results are wrapped in an array to make it possible
                // to distinguish between faults and regular structs.
                $responses[] = array($result);
            } catch (\Exception $error) {
                $responses[] = $error;
            }
        }
        return $responses;
    }

Perform several calls to XML-RPC methods
in a single go.

\param array $requests
Array of requests, each described as a struct
with the following information:
- "methodName": name of the method to call
- "params": array of parameters for the method

\retval array
Array of responses, one for each request,
in the same order.
Each response may be either a fault or an array
with a single element (the call's result).

\note
Recursive calls to system.multicall are forbidden.

Perform several calls to XML - RPC methods in a single go .


public static function load($class)
    {
        // This code only applies to PHP 5.3.7 & 5.3.8.
        // It prevents a case of remote code execution (CVE 2011-3379).
        if (strpos($class, ':') !== false) {
            // @codeCoverageIgnoreStart
            throw new \Exception('Possible remote execution attempt');
            // @codeCoverageIgnoreEnd
        }

        $class = ltrim($class, '\\');
        if (strncmp($class, 'fpoirotte\\XRL\\', 14)) {
            return false;
        }

        $class = substr($class, 14);
        if (!strncmp($class, 'tests\\', 6)) {
            $path = dirname(__DIR__);
        } else {
            $path = __DIR__;
        }

        $class = str_replace(array('_', '\\'), DIRECTORY_SEPARATOR, $class);
        include($path . DIRECTORY_SEPARATOR . $class . '.php');
        $res = (class_exists($class, false) || interface_exists($class, false));
        return $res;
    }

Load an XRL class or interface.

\param string $class
Name of the class/interface to load.

\note
The autoloader will only try to load classes/interfaces
whose name starts with "fpoirotte\\XRL\\" (case-sensitive).

\warning
The autoloader will throw an exception (which will
most likely result in a fatal error in your application)
in case the class or interface's name contains a colon.
This is a protection against a possible remote inclusion
vulnerability introduced in PHP 5.3.8 using is_a().

\retval bool
\c true if the class or interface could be loaded,
\c false otherwise.


public static function getVersion()
    {
        static $version = null;

        // Return cached version if possible.
        if (null !== $version) {
            return $version;
        }

        // From a phar release.
        if (!strncmp('phar://', __FILE__, 7)) {
            $phar = new \Phar(dirname(__DIR__));
            $md = $phar->getMetadata();
            $version = $md['version'];
        } else {
            // From a composer install.
            $getver = dirname(__DIR__) .
                        DIRECTORY_SEPARATOR . 'vendor' .
                        DIRECTORY_SEPARATOR . 'erebot' .
                        DIRECTORY_SEPARATOR . 'buildenv' .
                        DIRECTORY_SEPARATOR . 'get_version.php';
            if (file_exists($getver)) {
                $version = trim(shell_exec($getver));
            } else {
                // Default guess
                $version = 'dev';
            }
        }

        return $version;
    }

public
static
function
getVersion
(
)
{
static
$
version
=
;
// Return cached version if possible.
if
(
!==
$
version
)
{
return
$
version
;
}
// From a phar release.
if
(
!
strncmp
(
'phar://'
,
__FILE__
,
7
)
)
{
$
phar
=
new
\
Phar
(
dirname
(
__DIR__
)
)
;
$
md
=
$
phar
->
getMetadata
(
)
;
$
version
=
$
md
[
'version'
]
;
}
else
{
// From a composer install.
$
getver
=
dirname
(
__DIR__
)
.
DIRECTORY_SEPARATOR
.
'vendor'
.
DIRECTORY_SEPARATOR
.
'erebot'
.
DIRECTORY_SEPARATOR
.
'buildenv'
.
DIRECTORY_SEPARATOR
.
'get_version.php'
;
if
(
file_exists
(
$
getver
)
)
{
$
version
=
trim
(
shell_exec
(
$
getver
)
)
;
}
else
{
// Default guess
$
version
=
'dev'
;
}
}
return
$
version
;
}

Return XRL's version.

\retval string
XRL's version, or "dev" if the version
information could not be retrieved.


public function printUsage($output, $prog)
    {
        $usageFile  = dirname(__DIR__) .
                        DIRECTORY_SEPARATOR . 'data' .
                        DIRECTORY_SEPARATOR . 'usage.txt';
        $usage      = @file_get_contents($usageFile);
        $usage      = str_replace(array("\r\n", "\r"), "\n", $usage);
        $usage      = trim($usage);
        $output->write($usage, $prog, 'http://xmlrpc.example.com/');
    }

public function printUsage ( $ output , $ prog ) { $ usageFile = dirname ( __DIR__ ) . DIRECTORY_SEPARATOR . 'data' . DIRECTORY_SEPARATOR . 'usage.txt' ; $ usage = @ file_get_contents ( $ usageFile ) ; $ usage = str_replace ( array ( "\r\n" , "\r" ) , "\n" , $ usage ) ; $ usage = trim ( $ usage ) ; $ output -> write ( $ usage , $ prog , 'http://xmlrpc.example.com/' ) ; }

Display this script's usage.

\param fpoirotte::XRL::Output $output
Output where usage information
will be sent.

\param string $prog
The name of this script, ie.
\c $_SERVER['argv'][0]


protected function parseBool($value)
    {
        $value = strtolower($value);
        if (in_array($value, array('0', 'off', 'false'))) {
            return false;
        }
        if (in_array($value, array('1', 'on', 'true'))) {
            return true;
        }
        throw new \Exception('Invalid value "'.$value.'" for type "bool"');
    }

protected
function
parseBool
(
$
value
)
{
$
value
=
strtolower
(
$
value
)
;
if
(
in_array
(
$
value
,
array
(
'0'
,
'off'
,
'false'
)
)
)
{
return
false
;
}
if
(
in_array
(
$
value
,
array
(
'1'
,
'on'
,
'true'
)
)
)
{
return
true
;
}
throw
new
\
Exception
(
'Invalid value "'
.
$
value
.
'" for type "bool"'
)
;
}

Parse a boolean out of some text.
"0", "off" or "false" can be used to represent
\c false while "1", "on" or "true" can used to
represent \c true.

\param string $value
Some text that's supposed to represent
a boolean value.

\retval bool
The value that was parsed.

\throw Exception
The given text did not contain
a boolean value.

Parse a boolean out of some text . 0 off or false can be used to represent \ c false while 1 on or true can used to represent \ c true .


protected function parseFile($value)
    {
        $content = @file_get_contents($value);
        if ($content === false) {
            throw new \Exception('Could not read content of "'.$value.'"');
        }
        return $content;
    }

protected
function
parseFile
(
$
value
)
{
$
content
=
@
file_get_contents
(
$
value
)
;
if
(
$
content
===
false
)
{
throw
new
\
Exception
(
'Could not read content of "'
.
$
value
.
'"'
)
;
}
return
$
content
;
}

Return the content of a file.

\param string $value
Name of the file to read.

\retval string
The content of that file.

\throw Exception
The file did not exist or its content
could not be read.


protected function parse(array $args)
    {
        $params     = array(
            'serverURL'     => null,
            'procedure'     => null,
            'additional'    => array(),
        );
        $options    = array(
            'd' => false,
            'h' => false,
            'n' => false,
            't' => new \DateTimeZone(@date_default_timezone_get()),
            'v' => 0,
            'V' => false,
            'x' => false,
        );

        while (count($args)) {
            $v = array_shift($args);

            if ($params['serverURL'] === null) {
                if (substr($v, 0, 1) == '-') {
                    $p = array();
                    $v = (string) substr($v, 1);
                    foreach (str_split($v) as $o) {
                        if (!array_key_exists($o, $options)) {
                            throw new \Exception(
                                'Unknown option "'.$o.'". '.
                                'Use -h to get help.'
                            );
                        }

                        if (is_bool($options[$o])) {
                            $options[$o] = true;
                        } elseif (is_int($options[$o])) {
                            $options[$o]++;
                        } else {
                            $p[] = $o;
                        }
                    }

                    foreach ($p as $o) {
                        if (!count($args)) {
                            throw new \Exception(
                                'Not enough arguments for option "'.$o.'".'
                            );
                        }
                        $v = array_shift($args);
                        if (!($options[$o] instanceof \DateTimeZone)) {
                            $options[$o] = new \DateTimeZone($v);
                        }
                    }
                } else {
                    $params['serverURL'] = $v;
                }
                continue;
            }

            if ($params['procedure'] === null) {
                $params['procedure'] = $v;
                break;
            }
        }

        while (count($args)) {
            $params['additional'][] = $this->parseParam($args, $options['t']);
        }

        return array($options, $params);
    }

protected
function
parse
(
array
$
args
)
{
$
params
=
array
(
'serverURL'
=>
,
'procedure'
=>
,
'additional'
=>
array
(
)
,
)
;
$
options
=
array
(
'd'
=>
false
,
'h'
=>
false
,
'n'
=>
false
,
't'
=>
new
\
DateTimeZone
(
@
date_default_timezone_get
(
)
)
,
'v'
=>
0
,
'V'
=>
false
,
'x'
=>
false
,
)
;
while
(
count
(
$
args
)
)
{
$
v
=
array_shift
(
$
args
)
;
if
(
$
params
[
'serverURL'
]
===
)
{
if
(
substr
(
$
v
,
0
,
1
)
==
'-'
)
{
$
p
=
array
(
)
;
$
v
=
(
string
)
substr
(
$
v
,
1
)
;
foreach
(
str_split
(
$
v
)
as
$
o
)
{
if
(
!
array_key_exists
(
$
o
,
$
options
)
)
{
throw
new
\
Exception
(
'Unknown option "'
.
$
o
.
'". '
.
'Use -h to get help.'
)
;
}
if
(
is_bool
(
$
options
[
$
o
]
)
)
{
$
options
[
$
o
]
=
true
;
}
elseif
(
is_int
(
$
options
[
$
o
]
)
)
{
$
options
[
$
o
]
++
;
}
else
{
$
p
[
]
=
$
o
;
}
}
foreach
(
$
p
as
$
o
)
{
if
(
!
count
(
$
args
)
)
{
throw
new
\
Exception
(
'Not enough arguments for option "'
.
$
o
.
'".'
)
;
}
$
v
=
array_shift
(
$
args
)
;
if
(
!
(
$
options
[
$
o
]
instanceof
\
DateTimeZone
)
)
{
$
options
[
$
o
]
=
new
\
DateTimeZone
(
$
v
)
;
}
}
}
else
{
$
params
[
'serverURL'
]
=
$
v
;
}
continue
;
}
if
(
$
params
[
'procedure'
]
===
)
{
$
params
[
'procedure'
]
=
$
v
;
break
;
}
}
while
(
count
(
$
args
)
)
{
$
params
[
'additional'
]
[
]
=
$
this
->
parseParam
(
$
args
,
$
options
[
't'
]
)
;
}
return
array
(
$
options
,
$
params
)
;
}

Parse the arguments passed to this script.

\param array $args
A list with the arguments passed to this
script.

\retval array
An array of <tt>($options,$params)</tt>
for this script.

\throw Exception
Some error occurred during the parsing.
See the exception's message for more
information.

Parse the arguments passed to this script .


public function run(array $args)
    {
        $prog = array_shift($args);
        try {
            list($options, $params) = $this->parse($args);
        } catch (\Exception $e) {
            fprintf(STDERR, '%s: %s' . PHP_EOL, $prog, $e->getMessage());
            return 2;
        }

        // Show help.
        if ($options['h']) {
            $this->printUsage(new \fpoirotte\XRL\Output(STDOUT), $prog);
            return 0;
        }

        // Show version.
        if ($options['V']) {
            $version = self::getVersion();
            $license = self::getCopyrightAndLicense();
            echo 'XRL version ' . $version . PHP_EOL;
            echo PHP_EOL . $license . PHP_EOL;
            echo 'Visit https://github.com/fpoirotte/XRL for more!' . PHP_EOL;
            return 0;
        }

        // Do we have enough arguments to do something?
        if ($params['serverURL'] === null || $params['procedure'] === null) {
            $this->printUsage(new \fpoirotte\XRL\Output(STDERR), $prog);
            return 2;
        }

        // Then let's do it!
        $encoder    = new \fpoirotte\XRL\NativeEncoder(new \fpoirotte\XRL\Encoder($options['t'], true));
        $decoder    = new \fpoirotte\XRL\NativeDecoder(new \fpoirotte\XRL\Decoder($options['t'], $options['x']));
        $request    = new \fpoirotte\XRL\Request($params['procedure'], $params['additional']);

        // Change verbosity as necessary.
        if (class_exists('\\Plop\\Plop')) {
            $logging = \Plop\Plop::getInstance();
            $logging->getLogger()->setLevel(40 - min(4, $options['v']) * 10);
        } else {
            $logging = null;
        }

        // Prepare the request.
        $xml = $encoder->encodeRequest($request);
        $logging and $logging->debug(
            "Request:\n%(request)s",
            array('request' => $xml)
        );
        if ($options['n']) {
            echo 'Not sending the actual query due to dry run mode.' . PHP_EOL;
            return 0;
        }

        $headers    = array(
            'Content-Type: text/xml',
            'User-Agent: XRL/' . static::getVersion(),
        );

        // Prepare the context.
        $ctxOptions = array(
            'http' => array(
                'method'    => 'POST',
                'content'   => $xml,
                'header'    => $headers,
            ),
        );
        $context = stream_context_create($ctxOptions);
        libxml_set_streams_context($context);

        // Send the request and process the response.
        try {
            $result = $decoder->decodeResponse($params['serverURL']);
        } catch (\Exception $result) {
            // Nothing to do.
        }

        echo 'Result:' . PHP_EOL . print_r($result, true) . PHP_EOL;
        return 0;
    }

Run this CLI script.

\param array $args
A list of arguments passed to this script.

\retval int
Exit code. \c 0 is used to indicate a
success, while any other code indicates
an error.

\note
In case of an error, additional messages
may be sent to \c STDERR by this script.


public function resolved(string $id): bool
    {
        if (!$this->has($id)) {
            throw new class extends \LogicException implements NotFoundExceptionInterface {};
        }

        return !$this->container[$id] instanceof \Closure;
    }

public function resolved ( string $ id ) : bool { if ( ! $ this -> has ( $ id ) ) { throw new class extends \ LogicException implements NotFoundExceptionInterface { } ; } return ! $ this -> container [ $ id ] instanceof \ Closure ; }

Returns whether a given service has already been resolved
into its final value, or is still a callable.

@throws NotFoundExceptionInterface No entry was found for **this** identifier.

Returns whether a given service has already been resolved into its final value or is still a callable .


protected function getWriter()
    {
        $writer = new \XMLWriter();
        $writer->openMemory();
        if ($this->indent) {
            $writer->setIndent(true);
            $writer->startDocument('1.0', 'UTF-8');
        } else {
            $writer->setIndent(false);
            $writer->startDocument();
        }
        return $writer;
    }

protected function getWriter ( ) { $ writer = new \ XMLWriter ( ) ; $ writer -> openMemory ( ) ; if ( $ this -> indent ) { $ writer -> setIndent ( true ) ; $ writer -> startDocument ( '1.0' , 'UTF-8' ) ; } else { $ writer -> setIndent ( false ) ; $ writer -> startDocument ( ) ; } return $ writer ; }

Return an XML writer that will be used
to produce XML-RPC requests and responses.

\retval XMLWriter
XML writer to use to produce documents.

Return an XML writer that will be used to produce XML - RPC requests and responses .


protected function finalizeWrite(\XMLWriter $writer)
    {
        $writer->endDocument();
        $result = $writer->outputMemory(true);

        if (!$this->indent) {
            // Remove the XML declaration for an even
            // more compact result.
            if (!strncmp($result, '<'.'?xml', 5)) {
                $pos    = strpos($result, '?'.'>');
                if ($pos !== false) {
                    $result = (string) substr($result, $pos + 2);
                }
            }
            // Remove leading & trailing whitespace.
            $result = trim($result);
        }

        return $result;
    }

This method must be called when the document
is complete and returns the document.

\param XMLWriter $writer
XML writer used to produce the document.

\retval string
The XML document that was generated,
as serialized XML.

This method must be called when the document is complete and returns the document .