public function remove($id)
    {
        $success = false;
        foreach ($this->items as $i => $item) {
            if ($item->getFeedId() === $id) {
                unset($this->items[$i]);
                $success = true;
                break;
            }
        }

        if (false === $success) {
            throw new \InvalidArgumentException('Unknown item');
        }

        return $this;
    }

public
function
remove
(
$
id
)
{
$
success
=
false
;
foreach
(
$
this
->
items
as
$
i
=>
$
item
)
{
if
(
$
item
->
getFeedId
(
)
===
$
id
)
{
unset
(
$
this
->
items
[
$
i
]
)
;
$
success
=
true
;
break
;
}
}
if
(
false
===
$
success
)
{
throw
new
\
InvalidArgumentException
(
'Unknown item'
)
;
}
return
$
this
;
}

Removes an item by Id

@throws \InvalidArgumentException
@param $id
@return Feed


public function replace($id, ItemInterface $newItem)
    {
        $success = false;
        foreach ($this->items as $i => $item) {
            if ($item->getFeedId() == $id) {
                $this->items[$i] = $newItem;
                $success = true;
                break;
            }
        }

        if (false === $success) {
            throw new \InvalidArgumentException('Unknown item');
        }

        return $this;
    }

public
function
replace
(
$
id
,
ItemInterface
$
newItem
)
{
$
success
=
false
;
foreach
(
$
this
->
items
as
$
i
=>
$
item
)
{
if
(
$
item
->
getFeedId
(
)
==
$
id
)
{
$
this
->
items
[
$
i
]
=
$
newItem
;
$
success
=
true
;
break
;
}
}
if
(
false
===
$
success
)
{
throw
new
\
InvalidArgumentException
(
'Unknown item'
)
;
}
return
$
this
;
}

Replace an Item by an other

@throws \InvalidArgumentException
@param $id
@param ItemInterface $newItem
@return Feed


public function merge(Feed $feed)
    {
        $this->items = array();

        foreach ($feed as $item) {
            $this->add($item);
        }

        return $this;
    }

public function merge ( Feed $ feed ) { $ this -> items = array ( ) ; foreach ( $ feed as $ item ) { $ this -> add ( $ item ) ; } return $ this ; }

Merge 2 feeds

@param Feed $feed
@return Feed


protected function autoSlice()
    {
        $maxItems = $this->get('max_items', 10);
        if (count($this) > $maxItems) {
            $this->items = array_slice(
                $this->items,
                count($this) - $maxItems,
                $maxItems
            );
        }

        return $this;
    }

protected function autoSlice ( ) { $ maxItems = $ this -> get ( 'max_items' , 10 ) ; if ( count ( $ this ) > $ maxItems ) { $ this -> items = array_slice ( $ this -> items , count ( $ this ) - $ maxItems , $ maxItems ) ; } return $ this ; }

Auto slice the items to keep the good number of items
@return Feed


public function getConflicts() {
		$dbr = $this->getDBSlave();

		// Join against the user table to ensure that we skip stray
		// entries left after an account is renamed or otherwise munged.
		$spoofedUsers = $dbr->select(
			[ 'spoofuser', $this->getTableName() ],
			[ 'su_name' ], // Same thing due to the join. Saves extra variableness
			[
				'su_normalized' => $this->normalized,
				'su_name = ' . $this->getUserColumn(),
			],
			__METHOD__,
			[
				'LIMIT' => 5
			] );

		$spoofs = [];
		foreach ( $spoofedUsers as $row ) {
			array_push( $spoofs, $row->su_name );
		}
		return $spoofs;
	}

Does the username pass Unicode legality and script-mixing checks?

@return array empty if no conflict, or array containing conflicting usernames

Does the username pass Unicode legality and script - mixing checks?


public static function batchRecord( IDatabase $dbw, $items ) {
		if ( !count( $items ) ) {
			return false;
		}
		$fields = [];
		/**
		 * @var $item SpoofUser
		 */
		foreach ( $items as $item ) {
			$fields[] = $item->insertFields();
		}
		$dbw->replace(
			'spoofuser',
			[ 'su_name' ],
			$fields,
			__METHOD__ );
		return true;
	}

Insert a batch of spoof normalization records into the database.
@param IDatabase $dbw
@param SpoofUser[] $items
@return bool

Insert a batch of spoof normalization records into the database .


private function writeItems(XMLManager $xml, Feed $feed)
    {
        foreach ($feed as $item) {
            $this->writeItem($xml, $item);
        }
    }

private function writeItems ( XMLManager $ xml , Feed $ feed ) { foreach ( $ feed as $ item ) { $ this -> writeItem ( $ xml , $ item ) ; } }

Write Feed Items

@param \Nekland\Bundle\FeedBundle\XML\XMLManager $xml
@param \Nekland\Bundle\FeedBundle\Feed           $feed
@return void


protected function setCurrent()
    {
        if(count($this->buffer) === 0)
        {
            $this->buffer();
        }

        $this->current = count($this->buffer) > 0 ? array_pop($this->buffer) : null;
    }

protected function setCurrent ( ) { if ( count ( $ this -> buffer ) === 0 ) { $ this -> buffer ( ) ; } $ this -> current = count ( $ this -> buffer ) > 0 ? array_pop ( $ this -> buffer ) : null ; }


protected function buffer()
    {
        $this->buffer = $this->scheduleManager->findSchedules($this->limit, $this->offset);

        $this->offset += count($this->buffer);
    }

protected function buffer ( ) { $ this -> buffer = $ this -> scheduleManager -> findSchedules ( $ this -> limit , $ this -> offset ) ; $ this -> offset += count ( $ this -> buffer ) ; }


public function sortByDate()
    {
        return $this->usort(function ($a, $b) {
            if (!isset($a['date'])) {
                return -1;
            }
            if (!isset($b['date'])) {
                return 1;
            }
            if ($a['date'] == $b['date']) {
                return 0;
            }

            return ($a['date'] > $b['date']) ? -1 : 1;
        });
    }

public function sortByDate ( ) { return $ this -> usort ( function ( $ a , $ b ) { if ( ! isset ( $ a [ 'date' ] ) ) { return - 1 ; } if ( ! isset ( $ b [ 'date' ] ) ) { return 1 ; } if ( $ a [ 'date' ] == $ b [ 'date' ] ) { return 0 ; } return ( $ a [ 'date' ] > $ b [ 'date' ] ) ? - 1 : 1 ; } ) ; }


public function import($config)
    {
        if (is_array($config)) {
            $data = $this->getAll();
            $origin = $data->export();
            $data->import($config);
            $data->import($origin);
            $this->setFromData($data);
        }
    }

public function import ( $ config ) { if ( is_array ( $ config ) ) { $ data = $ this -> getAll ( ) ; $ origin = $ data -> export ( ) ; $ data -> import ( $ config ) ; $ data -> import ( $ origin ) ; $ this -> setFromData ( $ data ) ; } }

Import array config to current config.

@param array $config

@return $this


protected function setFromData(Data $data)
    {
        if ($this->data !== $data) {
            $this->data = $data;
        }

        return $this;
    }

protected function setFromData ( Data $ data ) { if ( $ this -> data !== $ data ) { $ this -> data = $ data ; } return $ this ; }

Set config data.

@param Data $data

@return $this


public function setSourceDir($sourceDir = null)
    {
        if ($sourceDir === null) {
            $sourceDir = getcwd();
        }
        if (!is_dir($sourceDir)) {
            throw new \InvalidArgumentException(sprintf("'%s' is not a valid source directory.", $sourceDir));
        }
        $this->sourceDir = $sourceDir;

        return $this;
    }

public
function
setSourceDir
(
$
sourceDir
=
)
{
if
(
$
sourceDir
===
)
{
$
sourceDir
=
getcwd
(
)
;
}
if
(
!
is_dir
(
$
sourceDir
)
)
{
throw
new
\
InvalidArgumentException
(
sprintf
(
"'%s' is not a valid source directory."
,
$
sourceDir
)
)
;
}
$
this
->
sourceDir
=
$
sourceDir
;
return
$
this
;
}

Set source directory.

@param null $sourceDir

@throws Exception

@return $this


public function setDestinationDir($destinationDir = null)
    {
        if ($destinationDir === null) {
            $destinationDir = $this->sourceDir;
        }
        if (!is_dir($destinationDir)) {
            throw new \InvalidArgumentException(sprintf("'%s' is not a valid destination directory.", $destinationDir));
        }
        $this->destinationDir = $destinationDir;

        return $this;
    }

Set destination directory.

@param null $destinationDir

@throws Exception

@return $this


public function finder(Page $page, Config $config)
    {
        $layout = 'unknown';

        // what layouts could be use for the page?
        $layouts = self::fallback($page);

        // take the first available layout
        foreach ($layouts as $layout) {
            // is it in layouts/ dir?
            if (Util::getFS()->exists($config->getLayoutsPath().'/'.$layout)) {
                return $layout;
            }
            // is it in <theme>/layouts/ dir?
            if ($config->hasTheme()) {
                $themes = $config->getTheme();
                foreach ($themes as $theme) {
                    if (Util::getFS()->exists($config->getThemeDirPath($theme, 'layouts').'/'.$layout)) {
                        return $layout;
                    }
                }
            }
            // is it in res/layouts/ dir?
            if (Util::getFS()->exists($config->getInternalLayoutsPath().'/'.$layout)) {
                return $layout;
            }
        }

        throw new Exception(sprintf("Layout '%s' not found for page '%s'!", $layout, $page->getId()));
    }

Layout file finder.

@param Page   $page
@param Config $config

@throws Exception

@return string


protected static function fallback(Page $page)
    {
        // remove redundant '.twig' extension
        $layout = str_replace('.twig', '', $page->getLayout());

        switch ($page->getNodeType()) {
            case NodeType::HOMEPAGE:
                $layouts = [
                    'index.html.twig',
                    '_default/list.html.twig',
                    '_default/page.html.twig',
                ];
                break;
            case NodeType::SECTION:
                $layouts = [
                    // 'section/$section.html.twig',
                    '_default/section.html.twig',
                    '_default/list.html.twig',
                ];
                if ($page->getPathname()) {
                    $section = explode('/', $page->getPathname())[0];
                    $layouts = array_merge(
                        [sprintf('section/%s.html.twig', $section)],
                        $layouts
                    );
                }
                break;
            case NodeType::TAXONOMY:
                $layouts = [
                    // 'taxonomy/$singular.html.twig',
                    '_default/taxonomy.html.twig',
                    '_default/list.html.twig',
                ];
                if ($page->getVariable('singular')) {
                    $layouts = array_merge(
                        [sprintf('taxonomy/%s.html.twig', $page->getVariable('singular'))],
                        $layouts
                    );
                }
                break;
            case NodeType::TERMS:
                $layouts = [
                    // 'taxonomy/$singular.terms.html.twig',
                    '_default/terms.html.twig',
                ];
                if ($page->getVariable('singular')) {
                    $layouts = array_merge(
                        [sprintf('taxonomy/%s.terms.html.twig', $page->getVariable('singular'))],
                        $layouts
                    );
                }
                break;
            default:
                $layouts = [
                    // '$section/$layout.twig',
                    // '$layout.twig',
                    // '$section/page.html.twig',
                    // 'page.html.twig',
                    '_default/page.html.twig',
                ];
                $layouts = array_merge(
                    ['page.html.twig'],
                    $layouts
                );

                if ($page->getSection()) {
                    $layouts = array_merge(
                        [sprintf('%s/page.html.twig', $page->getSection())],
                        $layouts
                    );
                }
                if ($page->getLayout()) {
                    $layouts = array_merge(
                        [sprintf('%s.twig', $layout)],
                        $layouts
                    );
                    if ($page->getSection()) {
                        $layouts = array_merge(
                            [sprintf('%s/%s.twig', $page->getSection(), $layout)],
                            $layouts
                        );
                    }
                }
        }

        return $layouts;
    }

Layout fall-back.

@param $page

@return string[]

@see finder()


public function parse()
    {
        $parser = new Parser($this->file);
        $parsed = $parser->parse();
        $this->frontmatter = $parsed->getFrontmatter();
        $this->body = $parsed->getBody();

        return $this;
    }

public function parse ( ) { $ parser = new Parser ( $ this -> file ) ; $ parsed = $ parser -> parse ( ) ; $ this -> frontmatter = $ parsed -> getFrontmatter ( ) ; $ this -> body = $ parsed -> getBody ( ) ; return $ this ; }


public function getSection()
    {
        if (empty($this->getVariable('section')) && !empty($this->path)) {
            $this->setSection(explode('/', $this->path)[0]);
        }

        return $this->getVariable('section');
    }

public function getSection ( ) { if ( empty ( $ this -> getVariable ( 'section' ) ) && ! empty ( $ this -> path ) ) { $ this -> setSection ( explode ( '/' , $ this -> path ) [ 0 ] ) ; } return $ this -> getVariable ( 'section' ) ; }


public function getPermalink()
    {
        if (empty($this->getVariable('permalink'))) {
            $this->setPermalink($this->getPathname());
        }

        return $this->getVariable('permalink');
    }

public function getPermalink ( ) { if ( empty ( $ this -> getVariable ( 'permalink' ) ) ) { $ this -> setPermalink ( $ this -> getPathname ( ) ) ; } return $ this -> getVariable ( 'permalink' ) ; }


public function setConfig($config)
    {
        if (!$config instanceof Config) {
            $config = new Config($config);
        }
        if ($this->config !== $config) {
            $this->config = $config;
        }

        return $this;
    }

public function setConfig ( $ config ) { if ( ! $ config instanceof Config ) { $ config = new Config ( $ config ) ; } if ( $ this -> config !== $ config ) { $ this -> config = $ config ; } return $ this ; }

Set config.

@param Config|array|null $config

@return $this


public function build($options)
    {
        // backward compatibility
        if ($options === true) {
            $options['verbosity'] = self::VERBOSITY_VERBOSE;
        }
        $this->options = array_merge([
            'verbosity' => self::VERBOSITY_NORMAL, // -1: quiet, 0: normal, 1: verbose, 2: debug
            'drafts'    => false, // build drafts or not
            'dry-run'   => false, // if dry-run is true, generated files are not saved
        ], $options);

        $steps = [];
        // init...
        foreach ($this->steps as $step) {
            /* @var $stepClass Step\StepInterface */
            $stepClass = new $step($this);
            $stepClass->init($this->options);
            $steps[] = $stepClass;
        }
        $this->steps = $steps;
        // ... and process!
        foreach ($this->steps as $step) {
            /* @var $step Step\StepInterface */
            $step->runProcess();
        }
        // show process time
        call_user_func_array($this->messageCallback, [
            'TIME',
            sprintf('Built in %ss', round(microtime(true) - $_SERVER['REQUEST_TIME_FLOAT'], 2)),
        ]);
        // show log
        $this->showLog($this->options['verbosity']);

        return $this;
    }

Builds a new website.

@param array $options

@return $this


public function getVersion()
    {
        if (!isset($this->version)) {
            try {
                $this->version = @file_get_contents(__DIR__.'/../VERSION');
                if ($this->version === false) {
                    throw new \Exception('Can\'t get version file!');
                }
            } catch (\Exception $e) {
                $this->version = self::VERSION;
            }
        }

        return $this->version;
    }

public
function
getVersion
(
)
{
if
(
!
isset
(
$
this
->
version
)
)
{
try
{
$
this
->
version
=
@
file_get_contents
(
__DIR__
.
'/../VERSION'
)
;
if
(
$
this
->
version
===
false
)
{
throw
new
\
Exception
(
'Can\'t get version file!'
)
;
}
}
catch
(
\
Exception
$
e
)
{
$
this
->
version
=
self
::
VERSION
;
}
}
return
$
this
->
version
;
}


public function filterBy($pages, $variable, $value)
    {
        $filteredPages = $pages->filter(function (Page $page) use ($variable, $value) {
            // filter virtual pages in section
            if ($variable == 'section' && $page->getVariable('virtual')) {
                return false;
            }
            // dedicated getter?
            $method = 'get'.ucfirst($variable);
            if (method_exists($page, $method) && $page->$method() == $value) {
                return true;
            }
            if ($page->getVariable($variable) == $value) {
                return true;
            }
        });

        return $filteredPages;
    }

public
function
filterBy
(
$
pages
,
$
variable
,
$
value
)
{
$
filteredPages
=
$
pages
->
filter
(
function
(
Page
$
page
)
use
(
$
variable
,
$
value
)
{
// filter virtual pages in section
if
(
$
variable
==
'section'
&&
$
page
->
getVariable
(
'virtual'
)
)
{
return
false
;
}
// dedicated getter?
$
method
=
'get'
.
ucfirst
(
$
variable
)
;
if
(
method_exists
(
$
page
,
$
method
)
&&
$
page
->
$
method
(
)
==
$
value
)
{
return
true
;
}
if
(
$
page
->
getVariable
(
$
variable
)
==
$
value
)
{
return
true
;
}
}
)
;
return
$
filteredPages
;
}

Filter by variable.

@param \PHPoole\Page\Collection $pages
@param string                   $variable
@param string                   $value

@throws Exception

@return array


public function sortByDate($array)
    {
        $callback = function ($a, $b) {
            if (!isset($a['date'])) {
                return -1;
            }
            if (!isset($b['date'])) {
                return 1;
            }
            if ($a['date'] == $b['date']) {
                return 0;
            }

            return ($a['date'] > $b['date']) ? -1 : 1;
        };

        if ($array instanceof Collection) {
            $array = $array->toArray();
        }
        if (is_array($array)) {
            usort($array, $callback);
        }

        return $array;
    }

public function sortByDate ( $ array ) { $ callback = function ( $ a , $ b ) { if ( ! isset ( $ a [ 'date' ] ) ) { return - 1 ; } if ( ! isset ( $ b [ 'date' ] ) ) { return 1 ; } if ( $ a [ 'date' ] == $ b [ 'date' ] ) { return 0 ; } return ( $ a [ 'date' ] > $ b [ 'date' ] ) ? - 1 : 1 ; } ; if ( $ array instanceof Collection ) { $ array = $ array -> toArray ( ) ; } if ( is_array ( $ array ) ) { usort ( $ array , $ callback ) ; } return $ array ; }

Sort by date.

@param $array|CollectionInterface

@return mixed


public function createUrl(\Twig_Environment $env, $value = null, $options = null)
    {
        $base = '';
        $baseurl = $env->getGlobals()['site']['baseurl'];
        $hash = md5($env->getGlobals()['site']['time']);
        $canonical = null;
        $addhash = true;

        if (isset($options['canonical'])) {
            $canonical = $options['canonical'];
        }
        if (is_bool($options)) { // backward compatibility
            $canonical = $options;
        }
        if (isset($options['addhash'])) {
            $addhash = $options['addhash'];
        }

        if ($env->getGlobals()['site']['canonicalurl'] === true || $canonical === true) {
            $base = rtrim($baseurl, '/');
        }
        if ($canonical === false) {
            $base = '';
        }

        if ($value instanceof Page) {
            $value = $value->getPermalink();
            if (false !== strpos($value, '.')) { // file URL (with a dot for extension)
                $url = $base.'/'.ltrim($value, '/');
            } else {
                $url = $base.'/'.ltrim(rtrim($value, '/').'/', '/');
            }
        } else {
            if (preg_match('~^(?:f|ht)tps?://~i', $value)) { // external URL
                $url = $value;
            } elseif (false !== strpos($value, '.')) { // file URL (with a dot for extension)
                $url = $base.'/'.ltrim($value, '/');
                if ($addhash) {
                    $url .= '?'.$hash;
                }
            } else {
                $value = $this->slugifyFilter($value);
                $url = $base.'/'.ltrim(rtrim($value, '/').'/', '/');
            }
        }

        return $url;
    }

public
function
createUrl
(
\
Twig_Environment
$
env
,
$
value
=
,
$
options
=
)
{
$
base
=
''
;
$
baseurl
=
$
env
->
getGlobals
(
)
[
'site'
]
[
'baseurl'
]
;
$
hash
=
md5
(
$
env
->
getGlobals
(
)
[
'site'
]
[
'time'
]
)
;
$
canonical
=
;
$
addhash
=
true
;
if
(
isset
(
$
options
[
'canonical'
]
)
)
{
$
canonical
=
$
options
[
'canonical'
]
;
}
if
(
is_bool
(
$
options
)
)
{
// backward compatibility
$
canonical
=
$
options
;
}
if
(
isset
(
$
options
[
'addhash'
]
)
)
{
$
addhash
=
$
options
[
'addhash'
]
;
}
if
(
$
env
->
getGlobals
(
)
[
'site'
]
[
'canonicalurl'
]
===
true
||
$
canonical
===
true
)
{
$
base
=
rtrim
(
$
baseurl
,
'/'
)
;
}
if
(
$
canonical
===
false
)
{
$
base
=
''
;
}
if
(
$
value
instanceof
Page
)
{
$
value
=
$
value
->
getPermalink
(
)
;
if
(
false
!==
strpos
(
$
value
,
'.'
)
)
{
// file URL (with a dot for extension)
$
url
=
$
base
.
'/'
.
ltrim
(
$
value
,
'/'
)
;
}
else
{
$
url
=
$
base
.
'/'
.
ltrim
(
rtrim
(
$
value
,
'/'
)
.
'/'
,
'/'
)
;
}
}
else
{
if
(
preg_match
(
'~^(?:f|ht)tps?://~i'
,
$
value
)
)
{
// external URL
$
url
=
$
value
;
}
elseif
(
false
!==
strpos
(
$
value
,
'.'
)
)
{
// file URL (with a dot for extension)
$
url
=
$
base
.
'/'
.
ltrim
(
$
value
,
'/'
)
;
if
(
$
addhash
)
{
$
url
.=
'?'
.
$
hash
;
}
}
else
{
$
value
=
$
this
->
slugifyFilter
(
$
value
)
;
$
url
=
$
base
.
'/'
.
ltrim
(
rtrim
(
$
value
,
'/'
)
.
'/'
,
'/'
)
;
}
}
return
$
url
;
}

Create an URL.

$options[
'canonical' => null,
'addhash'   => true,
];

@param \Twig_Environment         $env
@param string|\PHPoole\Page\Page $value
@param array|null                $options

@return string


public function minify($path)
    {
        $filePath = $this->destPath.'/'.$path;
        if (is_file($filePath)) {
            $extension = (new \SplFileInfo($filePath))->getExtension();
            switch ($extension) {
                case 'css':
                    $minifier = new Minify\CSS($filePath);
                    break;
                case 'js':
                    $minifier = new Minify\JS($filePath);
                    break;
                default:
                    throw new Exception(sprintf("File '%s' should be a '.css' or a '.js'!", $path));
            }
            $minifier->minify($filePath);

            return $path;
        }

        throw new Exception(sprintf("File '%s' doesn't exist!", $path));
    }

Minify a CSS or a JS file.

@param string $path

@throws Exception

@return string


public function toCss($path)
    {
        $filePath = $this->destPath.'/'.$path;
        $subPath = substr($path, 0, strrpos($path, '/'));

        if (is_file($filePath)) {
            $extension = (new \SplFileInfo($filePath))->getExtension();
            switch ($extension) {
                case 'scss':
                    $scssPhp = new Compiler();
                    $scssPhp->setImportPaths($this->destPath.'/'.$subPath);
                    $targetPath = preg_replace('/scss/m', 'css', $path);

                    // compile if target file doesn't exists
                    if (!$this->fileSystem->exists($this->destPath.'/'.$targetPath)) {
                        $scss = file_get_contents($filePath);
                        $css = $scssPhp->compile($scss);
                        $this->fileSystem->dumpFile($this->destPath.'/'.$targetPath, $css);
                    }

                    return $targetPath;
                    break;
                default:
                    throw new Exception(sprintf("File '%s' should be a '.scss'!", $path));
            }
        }

        throw new Exception(sprintf("File '%s' doesn't exist!", $path));
    }

Compile style file to CSS.

@param string $path

@throws Exception

@return string


public function readtime($text)
    {
        $words = str_word_count(strip_tags($text));
        $min = floor($words / 200);
        if ($min === 0) {
            return '1';
        }

        return $min;
    }

public function readtime ( $ text ) { $ words = str_word_count ( strip_tags ( $ text ) ) ; $ min = floor ( $ words / 200 ) ; if ( $ min === 0 ) { return '1' ; } return $ min ; }

Calculate estimated time to read a text.

@param $text

@return float|string

Calculate estimated time to read a text .


public function hashFile($path)
    {
        if (is_file($filePath = $this->destPath.'/'.$path)) {
            return sprintf('sha384-%s', base64_encode(hash_file('sha384', $filePath, true)));
        }
    }

public function hashFile ( $ path ) { if ( is_file ( $ filePath = $ this -> destPath . '/' . $ path ) ) { return sprintf ( 'sha384-%s' , base64_encode ( hash_file ( 'sha384' , $ filePath , true ) ) ) ; } }

Hash file with sha384.

@param string $path

@return string|null


protected function collectPages()
    {
        foreach ($this->phpoole->getPages() as $page) {
            /* @var $page \PHPoole\Collection\Page\Page */
            if (!empty($page['menu'])) {
                /*
                 * Single case
                 * ie:
                 * menu: main
                 */
                if (is_string($page['menu'])) {
                    $item = (new Entry($page->getId()))
                        ->setName($page->getTitle())
                        ->setUrl($page->getPermalink());
                    /* @var $menu \PHPoole\Collection\Menu\Menu */
                    $menu = $this->phpoole->getMenus()->get($page['menu']);
                    $menu->add($item);
                } else {
                    /*
                     * Multiple case
                     * ie:
                     * menu:
                     *     main:
                     *         weight: 1000
                     *     other
                     */
                    if (is_array($page['menu'])) {
                        foreach ($page['menu'] as $name => $value) {
                            $item = (new Entry($page->getId()))
                                ->setName($page->getTitle())
                                ->setUrl($page->getPermalink())
                                ->setWeight($value['weight']);
                            /* @var $menu \PHPoole\Collection\Menu\Menu */
                            $menu = $this->phpoole->getMenus()->get($name);
                            $menu->add($item);
                        }
                    }
                }
            }
        }
    }

/*
                 * Single case
                 * ie:
                 * menu: main
                 */


public function render($feed, $rendererName='rss')
    {
        $renderer = $this->getRenderer($rendererName);

        return $renderer->render($this->get($feed));
    }

public function render ( $ feed , $ rendererName = 'rss' ) { $ renderer = $ this -> getRenderer ( $ rendererName ) ; return $ renderer -> render ( $ this -> get ( $ feed ) ) ; }

Renders a feed

@param $feed
@param $rendererName

@return string


public function load($feedName, $loaderName = 'rss_file')
    {
        $loader = $this->getLoader($loaderName);
        $feed = $this->get($feedName);
        $loadedFeed = $loader->load($feed->getFilename($loader->getFormat()));

        return $this->feeds[$feedName] = $feed->merge($loadedFeed);
    }

public function load ( $ feedName , $ loaderName = 'rss_file' ) { $ loader = $ this -> getLoader ( $ loaderName ) ; $ feed = $ this -> get ( $ feedName ) ; $ loadedFeed = $ loader -> load ( $ feed -> getFilename ( $ loader -> getFormat ( ) ) ) ; return $ this -> feeds [ $ feedName ] = $ feed -> merge ( $ loadedFeed ) ; }

Loads a feed

@param $feedName
@param $loaderName
@return Feed


public function sniff($input)
    {
        if (is_array($input)) {
            return $this->sniffAll($input);
        }

        return $this->run($input);
    }

public function sniff ( $ input ) { if ( is_array ( $ input ) ) { return $ this -> sniffAll ( $ input ) ; } return $ this -> run ( $ input ) ; }

Start sniffing the content.

@param mixed $input

@return $type


public function is($input, $type)
    {
        if (!isset($this->types[$type])) {
            throw new \Exception('Type Not found use one of supported types ( '.implode(' , ', array_keys($this->types)).' )');
        }
        $typeClass = $this->types[$type];

        return (new $typeClass())->sniff($input);
    }

test against particular type.

@param mixed $input

@return bool


private function sniffAll(array $inputs)
    {
        $result = [];
        foreach ($inputs as $key => $input):
            $result[$key] = $this->run($input);
        endforeach;

        return $result;
    }

private function sniffAll ( array $ inputs ) { $ result = [ ] ; foreach ( $ inputs as $ key => $ input ) : $ result [ $ key ] = $ this -> run ( $ input ) ; endforeach ; return $ result ; }

Start Sniffing array.

@param array $inputs

@return array $result


private function run($input)
    {
        foreach ($this->types as $name => $typeClass):

            //check if it custom type closure
            if (is_object($typeClass) && $typeClass instanceof Closure) {
                if ($typeClass($input) === true) {
                    return $name;
                }
                continue;
            }

        if ((new $typeClass())->sniff($input) === true) {
            return $name;
        }

        endforeach;
        //nothing captuared
        return 'unknown';
    }

private
function
run
(
$
input
)
{
foreach
(
$
this
->
types
as
$
name
=>
$
typeClass
)
:
//check if it custom type closure
if
(
is_object
(
$
typeClass
)
&&
$
typeClass
instanceof
Closure
)
{
if
(
$
typeClass
(
$
input
)
===
true
)
{
return
$
name
;
}
continue
;
}
if
(
(
new
$
typeClass
(
)
)
->
sniff
(
$
input
)
===
true
)
{
return
$
name
;
}
endforeach
;
//nothing captuared
return
'unknown'
;
}

Run the tests on the input.

@param mixed $input

@return mixed result


public function save(ScheduleInterface $schedule, $andFlush = true)
    {
        $this->objectManager->persist($schedule);
        if ($andFlush)
        {
            $this->objectManager->flush();
        }
    }

public function save ( ScheduleInterface $ schedule , $ andFlush = true ) { $ this -> objectManager -> persist ( $ schedule ) ; if ( $ andFlush ) { $ this -> objectManager -> flush ( ) ; } }

Updates a schedule

@param ScheduleInterface $schedule
@param Boolean           $andFlush Whether to flush the changes (default true)


public function render(Feed $feed)
    {
        $filename = sprintf('%s/%s', $this->basePath, $feed->getFilename('rss'));
        if (is_file($filename)) {
            unlink($filename);
        }

        $xml = new XMLManager($filename);
        $this->init($xml, $feed);
        $this->writeItems($xml, $feed);
        $xml->save();
    }

public function render ( Feed $ feed ) { $ filename = sprintf ( '%s/%s' , $ this -> basePath , $ feed -> getFilename ( 'rss' ) ) ; if ( is_file ( $ filename ) ) { unlink ( $ filename ) ; } $ xml = new XMLManager ( $ filename ) ; $ this -> init ( $ xml , $ feed ) ; $ this -> writeItems ( $ xml , $ feed ) ; $ xml -> save ( ) ; }

Renders the feed

@param \Nekland\Bundle\FeedBundle\Feed $feed
@return void


private function createItem(XMLManager $xml)
    {
        $itemNode = $xml->getXml()->createElement('item');
        $channelNode = $xml->getXml()->getElementsByTagName('channel')->item(0);
        $channelNode->appendChild($itemNode);

        return $itemNode;
    }

private function createItem ( XMLManager $ xml ) { $ itemNode = $ xml -> getXml ( ) -> createElement ( 'item' ) ; $ channelNode = $ xml -> getXml ( ) -> getElementsByTagName ( 'channel' ) -> item ( 0 ) ; $ channelNode -> appendChild ( $ itemNode ) ; return $ itemNode ; }

Create an Item node

@param \Nekland\Bundle\FeedBundle\XML\XMLManager $xml
@return \DOMElement


private function getAuthor(ItemInterface $item)
    {
        $authorData = $item->getFeedAuthor();
        $author = '';
        if(isset($authorData['name'])) {
            $author .= $authorData['name'];
        }
        if (isset($authorData['email'])) {
            $author .= empty($author) ? $authorData['email'] : ' ' . $authorData['email'];
        }

        if(!empty($author)) {
            return $author;
        }

        return null;
    }

private
function
getAuthor
(
ItemInterface
$
item
)
{
$
authorData
=
$
item
->
getFeedAuthor
(
)
;
$
author
=
''
;
if
(
isset
(
$
authorData
[
'name'
]
)
)
{
$
author
.=
$
authorData
[
'name'
]
;
}
if
(
isset
(
$
authorData
[
'email'
]
)
)
{
$
author
.=
empty
(
$
author
)
$
authorData
[
'email'
]
:
' '
.
$
authorData
[
'email'
]
;
}
if
(
!
empty
(
$
author
)
)
{
return
$
author
;
}
return
;
}

Extract the author email

@param \Nekland\Bundle\FeedBundle\Item\ExtendedItemInterface $item
@return string|null


private function getComments(ItemInterface $item)
    {
        $commentRoute = $item->getFeedCommentRoute();
        if (!$commentRoute) {
            return null;
        } elseif (is_array($commentRoute)) {
            return $this->router->generate($commentRoute[0], $commentRoute[1]);
        } else {
            return $this->router->generate($commentRoute);
        }
    }

private function getComments ( ItemInterface $ item ) { $ commentRoute = $ item -> getFeedCommentRoute ( ) ; if ( ! $ commentRoute ) { return null ; } elseif ( is_array ( $ commentRoute ) ) { return $ this -> router -> generate ( $ commentRoute [ 0 ] , $ commentRoute [ 1 ] ) ; } else { return $ this -> router -> generate ( $ commentRoute ) ; } }

Extracts the Comments URI

@param \Nekland\Bundle\FeedBundle\Item\ExtendedItemInterface $item
@return null|string


protected function hasXMLSyntaxMarkers($content)
    {
        foreach (array('<', '&') as $char) {
            if (strpos($content, $char) !== false) {
                return true;
            }
        }

        return false;
    }

protected function hasXMLSyntaxMarkers ( $ content ) { foreach ( array ( '<' , '&' ) as $ char ) { if ( strpos ( $ content , $ char ) !== false ) { return true ; } } return false ; }

Check if the content has any XML syntax markers that would result in
invalid XML if inserted into an XML document. If it does, the content
should either be wrapped in a CDATA section or have all of it's
special XML characters converted into entities.

@param string $content
@return boolean

Check if the content has any XML syntax markers that would result in invalid XML if inserted into an XML document . If it does the content should either be wrapped in a CDATA section or have all of it s special XML characters converted into entities .


protected function collectTaxonomiesFromPages()
    {
        /* @var $page Page */
        foreach ($this->pageCollection as $page) {
            foreach (array_keys($this->config->get('site.taxonomies')) as $plural) {
                if (isset($page[$plural])) {
                    // converts a list to an array if necessary
                    if (!is_array($page[$plural])) {
                        $page->setVariable($plural, [$page[$plural]]);
                    }
                    foreach ($page[$plural] as $term) {
                        // adds each terms to the vocabulary collection
                        $this->taxonomies->get($plural)
                            ->add(new Term($term));
                        // adds each pages to the term collection
                        $this->taxonomies
                            ->get($plural)
                            ->get($term)
                            ->add($page);
                    }
                }
            }
        }
    }


protected function createNodePages()
    {
        /* @var $terms Vocabulary */
        foreach ($this->taxonomies as $plural => $terms) {
            if (count($terms) > 0) {
                /*
                 * Creates $plural/$term pages (list of pages)
                 * ex: /tags/tag-1/
                 */
                /* @var $pages PageCollection */
                foreach ($terms as $term => $pages) {
                    if (!$this->pageCollection->has($term)) {
                        $pages = $pages->sortByDate()->toArray();
                        $page = (new Page())
                            ->setId(Page::urlize(sprintf('%s/%s/', $plural, $term)))
                            ->setPathname(Page::urlize(sprintf('%s/%s', $plural, $term)))
                            ->setTitle(ucfirst($term))
                            ->setNodeType(NodeType::TAXONOMY)
                            ->setVariable('pages', $pages)
                            ->setVariable('date', $date = reset($pages)->getDate())
                            ->setVariable('singular', $this->config->get('site.taxonomies')[$plural])
                            ->setVariable('pagination', ['pages' => $pages]);
                        $this->generatedPages->add($page);
                    }
                }
                /*
                 * Creates $plural pages (list of terms)
                 * ex: /tags/
                 */
                $page = (new Page())
                    ->setId(Page::urlize($plural))
                    ->setPathname(strtolower($plural))
                    ->setTitle($plural)
                    ->setNodeType(NodeType::TERMS)
                    ->setVariable('plural', $plural)
                    ->setVariable('singular', $this->config->get('site.taxonomies')[$plural])
                    ->setVariable('terms', $terms)
                    ->setVariable('date', $date);

                // add page only if a template exist
                try {
                    $this->generatedPages->add($page);
                } catch (Exception $e) {
                    echo $e->getMessage()."\n";
                    // do not add page
                    unset($page);
                }
            }
        }
    }


protected function compileViews(): void
    {
        foreach ($this->laravel['view']->getFinder()->getPaths() as $path) {
            $this->compileViewsInPath($path);
        }
    }

protected function compileViews ( ) : void { foreach ( $ this -> laravel [ 'view' ] -> getFinder ( ) -> getPaths ( ) as $ path ) { $ this -> compileViewsInPath ( $ path ) ; } }


protected function compileViewsInPath(string $path): void
    {
        foreach ($this->laravel['files']->allFiles($path) as $file) {
            try {
                $engine = $this->laravel['view']->getEngineFromPath($file);
            } catch (InvalidArgumentException $e) {
                continue;
            }

            $this->compileSingleViewFile($engine, $file);
        }
    }

protected function compileViewsInPath ( string $ path ) : void { foreach ( $ this -> laravel [ 'files' ] -> allFiles ( $ path ) as $ file ) { try { $ engine = $ this -> laravel [ 'view' ] -> getEngineFromPath ( $ file ) ; } catch ( InvalidArgumentException $ e ) { continue ; } $ this -> compileSingleViewFile ( $ engine , $ file ) ; } }

Compile all views files in path.

@param  string  $path

@return void


protected function compileSingleViewFile($engine, string $file): void
    {
        if ($engine instanceof CompilerEngine) {
            $engine->getCompiler()->compile($file);
        }
    }

protected function compileSingleViewFile ( $ engine , string $ file ) : void { if ( $ engine instanceof CompilerEngine ) { $ engine -> getCompiler ( ) -> compile ( $ file ) ; } }

Compile single view file.

@param  mixed  $engine
@param  string  $file

@return void


public static function generate($before, $after)
    {
        if ($before === $after) {
            return '';
        }

        if (strlen($before) > self::MAX_SIZE || strlen($after) > self::MAX_SIZE) {
            return '';
        }

        $beforeTmpFile = tempnam(sys_get_temp_dir(), 'diff');
        file_put_contents($beforeTmpFile, $before);

        $afterTmpFile = tempnam(sys_get_temp_dir(), 'diff');
        file_put_contents($afterTmpFile, $after);

        $proc = new Process('git diff --no-index --exit-code -- '.escapeshellarg($beforeTmpFile).' '.escapeshellarg($afterTmpFile));
        $proc->run();

        @unlink($beforeTmpFile);
        @unlink($afterTmpFile);

        switch ($proc->getExitCode()) {
            // $before and $after were deemed identical. Should normally never
            // be reached as we already check for this above.
            case 0:
                return '';

            // The first four lines contain information about the files which were being compared.
            // We can savely trim them as we only generate the diff for one file.
            case 1:
                $output = explode("\n", $proc->getOutput());

                return implode("\n", array_slice($output, 4));

            default:
                throw new ProcessFailedException($proc);
        }
    }

Generates a DIFF.

@param string $before
@param string $after
@return string


public static function parse($diff)
    {
        if ('' === $diff) {
            return array();
        }

        $lines = explode("\n", $diff);
        $nbLines = count($lines);
        $curLine = 0;
        $chunks = array();

        while ($curLine < $nbLines) {
            $chunks[] = self::parseChunk($lines, $nbLines, $curLine);
        }

        return $chunks;
    }

public static function parse ( $ diff ) { if ( '' === $ diff ) { return array ( ) ; } $ lines = explode ( "\n" , $ diff ) ; $ nbLines = count ( $ lines ) ; $ curLine = 0 ; $ chunks = array ( ) ; while ( $ curLine < $ nbLines ) { $ chunks [ ] = self :: parseChunk ( $ lines , $ nbLines , $ curLine ) ; } return $ chunks ; }

Parser for Github's DIFF format.

@param string $diff
@return array an array of chunks


public function boot()
    {
        // Extension should be activated only if we're not running under
        // safe mode (or debug mode). This is to ensure that developer have
        // a way to disable broken extension without tempering the database.
        if (! ($this->booted() || $this->status->is('safe'))) {
            // Avoid extension booting being called more than once.
            $this->booted = true;

            $this->registerActiveExtensions();

            // Boot are executed once all extension has been registered. This
            // would allow extension to communicate with other extension
            // without having to known the registration dependencies.
            $this->dispatcher->boot();

            $this->events->dispatch('orchestra.extension: booted');
        }

        return $this;
    }


public function finish()
    {
        $this->extensions->each(function ($options, $name) {
            $this->dispatcher->finish($name, $options);
        });

        $this->extensions = new Collection();
        $this->booted = false;

        return $this;
    }

public function finish ( ) { $ this -> extensions -> each ( function ( $ options , $ name ) { $ this -> dispatcher -> finish ( $ name , $ options ) ; } ) ; $ this -> extensions = new Collection ( ) ; $ this -> booted = false ; return $ this ; }


protected function registerActiveExtensions(): void
    {
        $available = $this->memory->get('extensions.available', []);
        $active = $this->memory->get('extensions.active', []);

        // Loop all active extension and merge the configuration with
        // available config. Extension registration is handled by dispatcher
        // process due to complexity of extension boot process.

        Collection::make($active)->filter(function ($options, $name) use ($available) {
            return isset($available[$name]);
        })->map(function ($options, $name) use ($available) {
            $options['config'] = \array_merge(
                (array) $available[$name]['config'] ?? [],
                (array) $options['config'] ?? []
            );

            return $options;
        })->each(function ($options, $name) {
            $this->extensions->put($name, $options);
            $this->dispatcher->register($name, $options);
        });
    }

Register all active extension to dispatcher.

@return void

Register all active extension to dispatcher .


public function after(Closure $callback = null): void
    {
        if ($this->booted() || $this->status->is('safe')) {
            $this->app->call($callback);

            return;
        }

        $this->events->listen('orchestra.extension: booted', $callback);
    }

public
function
after
(
Closure
$
callback
=
)
:
void
{
if
(
$
this
->
booted
(
)
||
$
this
->
status
->
is
(
'safe'
)
)
{
$
this
->
app
->
call
(
$
callback
)
;
return
;
}
$
this
->
events
->
listen
(
'orchestra.extension: booted'
,
$
callback
)
;
}

Create an event listener or execute it directly.

@param  \Closure|null  $callback

@return void

Create an event listener or execute it directly .


public function provides(array $provides)
    {
        $this->compiled = Collection::make($provides)->mapWithKeys(function ($provider) {
            $options = $this->manifest[$provider] ?? $this->recompileProvider($provider);

            $this->loadDeferredServiceProvider($provider, $options);
            $this->loadEagerServiceProvider($provider, $options);
            $this->loadQueuedServiceProvider($provider, $options);

            return [$provider => Arr::except($options, ['instance'])];
        })->all();
    }

public function provides ( array $ provides ) { $ this -> compiled = Collection :: make ( $ provides ) -> mapWithKeys ( function ( $ provider ) { $ options = $ this -> manifest [ $ provider ] ?? $ this -> recompileProvider ( $ provider ) ; $ this -> loadDeferredServiceProvider ( $ provider , $ options ) ; $ this -> loadEagerServiceProvider ( $ provider , $ options ) ; $ this -> loadQueuedServiceProvider ( $ provider , $ options ) ; return [ $ provider => Arr :: except ( $ options , [ 'instance' ] ) ] ; } ) -> all ( ) ; }

Load available service providers.

@param  array  $provides

@return void


protected function writeManifestFile(array $manifest = [])
    {
        $this->files->put($this->manifestPath, '<?php return '.\var_export($manifest, true).';');
    }

protected
function
writeManifestFile
(
array
$
manifest
=
[
]
)
{
$
this
->
files
->
put
(
$
this
->
manifestPath
,
'<?php return '
.
\
var_export
(
$
manifest
,
true
)
.
';'
)
;
}

Write the manifest file.

@param  array  $manifest

@return void


protected function registerDeferredServiceProvider($provider, ServiceProvider $instance)
    {
        return [
            'instance' => $instance,
            'eager' => false,
            'when' => $instance->when(),
            'deferred' => \array_fill_keys($instance->provides(), $provider),
        ];
    }

protected function registerDeferredServiceProvider ( $ provider , ServiceProvider $ instance ) { return [ 'instance' => $ instance , 'eager' => false , 'when' => $ instance -> when ( ) , 'deferred' => \ array_fill_keys ( $ instance -> provides ( ) , $ provider ) , ] ; }

Register deferred service provider.

@param  string  $provider
@param  \Illuminate\Support\ServiceProvider  $instance

@return void


protected function loadQueuedServiceProvider($provider, array $options)
    {
        foreach ($options['when'] as $listen) {
            $this->events->listen($listen, function () use ($provider, $options) {
                $this->app->register($options['instance'] ?? $provider);
            });
        }
    }

protected function loadQueuedServiceProvider ( $ provider , array $ options ) { foreach ( $ options [ 'when' ] as $ listen ) { $ this -> events -> listen ( $ listen , function ( ) use ( $ provider , $ options ) { $ this -> app -> register ( $ options [ 'instance' ] ?? $ provider ) ; } ) ; } }

Load queued service provider.

@param  string  $provider
@param  array  $options

@return void


public function activate(Listener $listener, Fluent $extension)
    {
        if ($this->factory->started($extension->get('name'))) {
            return $listener->abortWhenRequirementMismatched();
        }

        return $this->execute($listener, 'activation', $extension, function (Factory $factory, $name) {
            $factory->activate($name);
        });
    }

public function activate ( Listener $ listener , Fluent $ extension ) { if ( $ this -> factory -> started ( $ extension -> get ( 'name' ) ) ) { return $ listener -> abortWhenRequirementMismatched ( ) ; } return $ this -> execute ( $ listener , 'activation' , $ extension , function ( Factory $ factory , $ name ) { $ factory -> activate ( $ name ) ; } ) ; }

Activate an extension.

@param  \Orchestra\Contracts\Extension\Listener\Activator  $listener
@param  \Illuminate\Support\Fluent  $extension

@return mixed


public function map(string $name, array $aliases): bool
    {
        $memory = $this->memory->make();
        $meta = $memory->get("extension_{$name}", []);

        foreach ($aliases as $current => $default) {
            isset($meta[$current]) && $this->config->set($default, $meta[$current]);

            $meta[$current] = $this->config->get($default);
        }

        $memory->put("extension_{$name}", $meta);

        return true;
    }

public function map ( string $ name , array $ aliases ) : bool { $ memory = $ this -> memory -> make ( ) ; $ meta = $ memory -> get ( "extension_{$name}" , [ ] ) ; foreach ( $ aliases as $ current => $ default ) { isset ( $ meta [ $ current ] ) && $ this -> config -> set ( $ default , $ meta [ $ current ] ) ; $ meta [ $ current ] = $ this -> config -> get ( $ default ) ; } $ memory -> put ( "extension_{$name}" , $ meta ) ; return true ; }

Map configuration to allow orchestra to store it in database.

@param  string  $name
@param  array   $aliases

@return bool

Map configuration to allow orchestra to store it in database .


public function registerDomainAwareness()
    {
        $this->app->resolving(RouteGenerator::class, function (RouteGenerator $generator, Application $app) {
            $generator->setBaseUrl($app->make('config')->get('app.url'));
        });
    }

public function registerDomainAwareness ( ) { $ this -> app -> resolving ( RouteGenerator :: class , function ( RouteGenerator $ generator , Application $ app ) { $ generator -> setBaseUrl ( $ app -> make ( 'config' ) -> get ( 'app.url' ) ) ; } ) ; }

Register domain awareness from configuration.

@return void

Register domain awareness from configuration .


public function detect(): Collection
    {
        $this->events->dispatch('orchestra.extension: detecting');

        return \tap($this->finder()->detect(), function ($extensions) {
            $this->memory->put('extensions.available', $extensions->map(function ($item) {
                return Arr::except($item, ['description', 'author', 'url', 'version']);
            })->all());
        });
    }

public
function
detect
(
)
:
Collection
{
$
this
->
events
->
dispatch
(
'orchestra.extension: detecting'
)
;
return
\
tap
(
$
this
->
finder
(
)
->
detect
(
)
,
function
(
$
extensions
)
{
$
this
->
memory
->
put
(
'extensions.available'
,
$
extensions
->
map
(
function
(
$
item
)
{
return
Arr
::
except
(
$
item
,
[
'description'
,
'author'
,
'url'
,
'version'
]
)
;
}
)
->
all
(
)
)
;
}
)
;
}

Detect all extensions.

@return \Illuminate\Support\Collection


public function option(string $name, string $option, $default = null)
    {
        if (! $this->extensions->has($name)) {
            return \value($default);
        }

        return Arr::get($this->extensions->get($name), $option, $default);
    }

public function option ( string $ name , string $ option , $ default = null ) { if ( ! $ this -> extensions -> has ( $ name ) ) { return \ value ( $ default ) ; } return Arr :: get ( $ this -> extensions -> get ( $ name ) , $ option , $ default ) ; }

Get an option for a given extension.

@param  string  $name
@param  string  $option
@param  mixed   $default

@return mixed


public function publish(string $name): void
    {
        $this->app->make('orchestra.publisher.migrate')->extension($name);
        $this->app->make('orchestra.publisher.asset')->extension($name);

        $this->events->dispatch('orchestra.publishing', [$name]);
        $this->events->dispatch("orchestra.publishing: {$name}");
    }

public
function
publish
(
string
$
name
)
:
void
{
$
this
->
app
->
make
(
'orchestra.publisher.migrate'
)
->
extension
(
$
name
)
;
$
this
->
app
->
make
(
'orchestra.publisher.asset'
)
->
extension
(
$
name
)
;
$
this
->
events
->
dispatch
(
'orchestra.publishing'
,
[
$
name
]
)
;
$
this
->
events
->
dispatch
(
"orchestra.publishing: {$name}"
)
;
}

Publish an extension.

@param  string

@return void


public function register(string $name, string $path): bool
    {
        return $this->finder()->registerExtension($name, $path);
    }

public function register ( string $ name , string $ path ) : bool { return $ this -> finder ( ) -> registerExtension ( $ name , $ path ) ; }

Register an extension.

@param  string  $name
@param  string  $path

@return bool


public function route(string $name, string $default = '/'): UrlGeneratorContract
    {
        // Boot the extension.
        ! $this->booted() && $this->app->make(LoadExtension::class)->bootstrap($this->app);

        if (! isset($this->routes[$name])) {

            // All route should be manage via `orchestra/extension::handles.{name}`
            // config key, except for orchestra/foundation.
            $key = "orchestra/extension::handles.{$name}";

            $prefix = $this->app->make('config')->get($key, $default);

            $this->routes[$name] = $this->app->make('orchestra.extension.url')->handle($prefix);
        }

        return $this->routes[$name];
    }

Get extension route handle.

@param  string   $name
@param  string   $default

@return \Orchestra\Contracts\Extension\UrlGenerator


protected function activating(string $name): bool
    {
        if (\is_null($active = $this->refresh($name))) {
            return false;
        }

        $this->extensions->put($name, $active[$name]);
        $this->publish($name);

        $this->dispatcher->activating($name, $active[$name]);

        return true;
    }

protected function activating ( string $ name ) : bool { if ( \ is_null ( $ active = $ this -> refresh ( $ name ) ) ) { return false ; } $ this -> extensions -> put ( $ name , $ active [ $ name ] ) ; $ this -> publish ( $ name ) ; $ this -> dispatcher -> activating ( $ name , $ active [ $ name ] ) ; return true ; }

Activating an extension.

@param  string  $name

@return bool


public function refresh(string $name): ?array
    {
        $memory = $this->memory;
        $available = $memory->get('extensions.available', []);
        $active = $memory->get('extensions.active', []);

        if (! isset($available[$name])) {
            return null;
        }

        // Append the activated extension to active extensions, and also
        // publish the extension (migrate the database and publish the
        // asset).
        if (! \is_null($handles = $active[$name]['config']['handles'] ?? null)) {
            Arr::set($available, "{$name}.config.handles", $handles);
        }

        $active[$name] = $available[$name];

        $memory->put('extensions.active', $active);

        return $active;
    }

Refresh extension configuration.

@param  string  $name

@return array|null


public function reset(string $name): bool
    {
        $memory = $this->memory;
        $default = $memory->get("extensions.available.{$name}", []);

        $memory->put("extensions.active.{$name}", $default);

        if ($memory->has("extension_{$name}")) {
            $memory->put("extension_{$name}", []);
        }

        return true;
    }

public function reset ( string $ name ) : bool { $ memory = $ this -> memory ; $ default = $ memory -> get ( "extensions.available.{$name}" , [ ] ) ; $ memory -> put ( "extensions.active.{$name}" , $ default ) ; if ( $ memory -> has ( "extension_{$name}" ) ) { $ memory -> put ( "extension_{$name}" , [ ] ) ; } return true ; }

Reset extension.

@param  string  $name

@return bool


public function handleExcludeField(EventInterface $event)
    {
        /** @var \Doctrine\ORM\Mapping\ClassMetadataInfo $metadata */
        $metadata    = $event->getParam('metadata');
        $identifiers = $metadata->getIdentifierFieldNames();

        return in_array($event->getParam('name'), $identifiers) &&
               ($metadata->generatorType === ClassMetadata::GENERATOR_TYPE_IDENTITY ||
                $metadata->generatorType === ClassMetadata::GENERATOR_TYPE_CUSTOM);
    }

Exclude GENERATOR_TYPE_IDENTITY && GENERATOR_TYPE_CUSTOM
Because most of the time they are custom auto-incrementers

@param  EventInterface $event
@internal
@return bool

Exclude GENERATOR_TYPE_IDENTITY && GENERATOR_TYPE_CUSTOM Because most of the time they are custom auto - incrementers


protected function createOrchestraDriver(): ThemeContract
    {
        $theme = new Theme(
            $this->app, $this->app->make('events'), $this->app->make('files')
        );

        return $theme->initiate();
    }

protected function createOrchestraDriver ( ) : ThemeContract { $ theme = new Theme ( $ this -> app , $ this -> app -> make ( 'events' ) , $ this -> app -> make ( 'files' ) ) ; return $ theme -> initiate ( ) ; }

Create an instance of the orchestra theme driver.

@return \Orchestra\Contracts\Theme\Theme

Create an instance of the orchestra theme driver .


public function bootstrap(Application $app)
    {
        $this->bootstrapConfiguration($app);

        $this->bootstrapForm($app);

        $this->bootstrapMenuHandler($app);

        $this->bootstrapSidebarPlaceholders($app);

        $this->bootstrapValidationRules($app);
    }

public function bootstrap ( Application $ app ) { $ this -> bootstrapConfiguration ( $ app ) ; $ this -> bootstrapForm ( $ app ) ; $ this -> bootstrapMenuHandler ( $ app ) ; $ this -> bootstrapSidebarPlaceholders ( $ app ) ; $ this -> bootstrapValidationRules ( $ app ) ; }

Bootstrap plugin.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function bootstrapConfiguration(Application $app)
    {
        if (empty($this->extension) || empty($this->config)) {
            return;
        }

        $app->make('orchestra.extension.config')->map($this->extension, $this->config);
    }

protected function bootstrapConfiguration ( Application $ app ) { if ( empty ( $ this -> extension ) || empty ( $ this -> config ) ) { return ; } $ app -> make ( 'orchestra.extension.config' ) -> map ( $ this -> extension , $ this -> config ) ; }

Bootstrap configuration.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function bootstrapForm(Application $app)
    {
        $this->attachListenerOn($app, 'form', function (Fluent $model, FormBuilder $form) {
            $this->form($model, $form);
        });
    }

protected function bootstrapForm ( Application $ app ) { $ this -> attachListenerOn ( $ app , 'form' , function ( Fluent $ model , FormBuilder $ form ) { $ this -> form ( $ model , $ form ) ; } ) ; }

Bootstrap the form.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function bootstrapMenuHandler(Application $app)
    {
        if (\is_null($this->menu)) {
            return;
        }

        $app->make('events')->listen('orchestra.ready: admin', $this->menu);
    }

protected
function
bootstrapMenuHandler
(
Application
$
app
)
{
if
(
\
is_null
(
$
this
->
menu
)
)
{
return
;
}
$
app
->
make
(
'events'
)
->
listen
(
'orchestra.ready: admin'
,
$
this
->
menu
)
;
}

Bootstrap menu handler.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function bootstrapSidebarPlaceholders(Application $app)
    {
        $widget = $app->make('orchestra.widget');
        $placeholder = $widget->make('placeholder.orchestra.extensions');

        $this->attachListenerOn($app, 'form', function () use ($placeholder) {
            foreach ($this->sidebar as $name => $view) {
                $placeholder->add($name)->value(\view($view));
            }
        });
    }

protected function bootstrapSidebarPlaceholders ( Application $ app ) { $ widget = $ app -> make ( 'orchestra.widget' ) ; $ placeholder = $ widget -> make ( 'placeholder.orchestra.extensions' ) ; $ this -> attachListenerOn ( $ app , 'form' , function ( ) use ( $ placeholder ) { foreach ( $ this -> sidebar as $ name => $ view ) { $ placeholder -> add ( $ name ) -> value ( \ view ( $ view ) ) ; } } ) ; }

Bootstrap sidebar placeholder.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function bootstrapValidationRules(Application $app)
    {
        $this->attachListenerOn($app, 'validate', function (Fluent $rules) {
            foreach ($this->rules as $name => $validation) {
                $rules[$name] = $validation;
            }
        });
    }

protected function bootstrapValidationRules ( Application $ app ) { $ this -> attachListenerOn ( $ app , 'validate' , function ( Fluent $ rules ) { foreach ( $ this -> rules as $ name => $ validation ) { $ rules [ $ name ] = $ validation ; } } ) ; }

Bootstrap validation rules.

@param  \Illuminate\Contracts\Foundation\Application  $app

@return void


protected function attachListenerOn(Application $app, $event, Closure $callback)
    {
        $app->make('events')->listen("orchestra.{$event}: extension.{$this->extension}", $callback);
    }

Attach event listener.

@param  \Illuminate\Contracts\Foundation\Application  $app
@param  string  $event
@param  \Closure  $callback

@return void


public function initiate()
    {
        $baseUrl = $this->app->make('request')->root();

        // Register relative and absolute URL for theme usage.
        $this->absoluteUrl = \rtrim($baseUrl, '/').'/themes';
        $this->relativeUrl = \trim(\str_replace($baseUrl, '/', $this->absoluteUrl), '/');

        return $this;
    }

Start theme engine, this should be called from application booted
or whenever we need to overwrite current active theme per request.

@return $this

Start theme engine this should be called from application booted or whenever we need to overwrite current active theme per request .


public function setTheme(?string $theme): void
    {
        if (! \is_null($this->theme)) {
            $this->resolved && $this->resetViewPaths();

            $this->dispatcher->dispatch("orchestra.theme.unset: {$this->theme}");
        }

        $this->theme = $theme;
        $this->dispatcher->dispatch("orchestra.theme.set: {$this->theme}");

        if ($this->resolved) {
            $this->resolved = false;
            $this->resolving();
        }
    }

public
function
setTheme
(
string
$
theme
)
:
void
{
if
(
!
\
is_null
(
$
this
->
theme
)
)
{
$
this
->
resolved
&&
$
this
->
resetViewPaths
(
)
;
$
this
->
dispatcher
->
dispatch
(
"orchestra.theme.unset: {$this->theme}"
)
;
}
$
this
->
theme
=
$
theme
;
$
this
->
dispatcher
->
dispatch
(
"orchestra.theme.set: {$this->theme}"
)
;
if
(
$
this
->
resolved
)
{
$
this
->
resolved
=
false
;
$
this
->
resolving
(
)
;
}
}

Set the theme, this would also load the theme manifest.

@param  string|null  $theme

@return void

Set the theme this would also load the theme manifest .


public function boot(): bool
    {
        if ($this->booted) {
            return false;
        }

        $this->booted = true;

        $themePath = $this->getThemePath();
        $autoload = $this->getThemeAutoloadFiles($themePath);

        foreach ($autoload as $file) {
            $file = \ltrim($file, '/');
            $this->files->requireOnce("{$themePath}/{$file}");
        }

        $this->dispatcher->dispatch("orchestra.theme.boot: {$this->theme}");

        return true;
    }

public
function
boot
(
)
:
bool
{
if
(
$
this
->
booted
)
{
return
false
;
}
$
this
->
booted
=
true
;
$
themePath
=
$
this
->
getThemePath
(
)
;
$
autoload
=
$
this
->
getThemeAutoloadFiles
(
$
themePath
)
;
foreach
(
$
autoload
as
$
file
)
{
$
file
=
\
ltrim
(
$
file
,
'/'
)
;
$
this
->
files
->
requireOnce
(
"{$themePath}/{$file}"
)
;
}
$
this
->
dispatcher
->
dispatch
(
"orchestra.theme.boot: {$this->theme}"
)
;
return
true
;
}

Boot and Load theme starter files.

@return bool


public function resolving(): bool
    {
        if ($this->resolved) {
            return false;
        }

        $this->resolved = true;

        $this->dispatcher->dispatch('orchestra.theme.resolving', [$this, $this->app]);

        $this->setViewPaths();

        return true;
    }

public function resolving ( ) : bool { if ( $ this -> resolved ) { return false ; } $ this -> resolved = true ; $ this -> dispatcher -> dispatch ( 'orchestra.theme.resolving' , [ $ this , $ this -> app ] ) ; $ this -> setViewPaths ( ) ; return true ; }


public function getAvailableThemePaths(): array
    {
        return Collection::make($this->getThemePaths())->filter(function ($path) {
            return $this->files->isDirectory($path);
        })->values()->all();
    }

public function getAvailableThemePaths ( ) : array { return Collection :: make ( $ this -> getThemePaths ( ) ) -> filter ( function ( $ path ) { return $ this -> files -> isDirectory ( $ path ) ; } ) -> values ( ) -> all ( ) ; }

Get available theme paths.

@return array


protected function getThemeAutoloadFiles(string $themePath): array
    {
        $manifest = new Manifest($this->files, $themePath);

        return $manifest->autoload ?? [];
    }

protected function getThemeAutoloadFiles ( string $ themePath ) : array { $ manifest = new Manifest ( $ this -> files , $ themePath ) ; return $ manifest -> autoload ?? [ ] ; }

Get theme autoload files from manifest.

@param  string $themePath

@return array

Get theme autoload files from manifest .


protected function validateProvidedTheme(string $group, $id, $theme): bool
    {
        if (! \in_array($group, $this->type)) {
            throw new InvalidArgumentException("Invalid theme name [{$group}], should either be 'frontend' or 'backend'.");
        }

        if (\is_null($theme)) {
            throw new InvalidArgumentException("Invalid Theme ID [{$id}], or is not available for '{$group}'.");
        }

        return true;
    }

Validate provided theme.

@param  string  $group
@param  string|int  $id
@param  object|null  $theme

@throws \InvalidArgumentException

@return bool


protected function getAvailableTheme(string $type): Collection
    {
        $themes = $this->finder->detect();

        return $themes->filter(function (Manifest $manifest) use ($type) {
            $group = $manifest->get('type');

            if (! empty($group) && ! \in_array($type, $group)) {
                return;
            }

            return $manifest;
        });
    }

protected function getAvailableTheme ( string $ type ) : Collection { $ themes = $ this -> finder -> detect ( ) ; return $ themes -> filter ( function ( Manifest $ manifest ) use ( $ type ) { $ group = $ manifest -> get ( 'type' ) ; if ( ! empty ( $ group ) && ! \ in_array ( $ type , $ group ) ) { return ; } return $ manifest ; } ) ; }

Get all available theme by type.

@param  string  $type

@return \Illuminate\Support\Collection


public function render(string $name, ...$parameters)
    {
        if (! isset($this->macros[$name])) {
            throw new BadMethodCallException("Method [$name] does not exist.");
        }

        return $this->macros[$name](...$parameters);
    }

public
function
render
(
string
$
name
,
...
$
parameters
)
{
if
(
!
isset
(
$
this
->
macros
[
$
name
]
)
)
{
throw
new
BadMethodCallException
(
"Method [$name] does not exist."
)
;
}
return
$
this
->
macros
[
$
name
]
(
...
$
parameters
)
;
}

Render the macro.

@param  string  $name
@param  mixed  $parameters

@throws \BadMethodCallException

@return string


public function filter($value)
    {
        /**
         * We try to create a \DateTime according to the format
         * If the creation fails, we return the string itself
         * so it's treated by Validate\Date
         */

        $date = (is_int($value))
            ? date_create("@$value") // from timestamp
            : DateTime::createFromFormat($this->format, $value);

        // Invalid dates can show up as warnings (ie. "2007-02-99")
        // and still return a DateTime object
        $errors = DateTime::getLastErrors();

        if ($errors['warning_count'] > 0 || $date === false) {
            return $value;
        }

        return $date;
    }

Converts a date string to a \DateTime
according to the date format given

@param  string $value
@return \DateTime|string

Converts a date string to a \ DateTime according to the date format given


protected function verifyStatus(): void
    {
        $config = $this->config->get('orchestra/extension::mode', 'normal');
        $input = $this->request->input('_mode', $config);

        if ($input == 'safe') {
            $this->enableSafeMode();
        } else {
            $this->disableSafeMode();
        }
    }

protected function verifyStatus ( ) : void { $ config = $ this -> config -> get ( 'orchestra/extension::mode' , 'normal' ) ; $ input = $ this -> request -> input ( '_mode' , $ config ) ; if ( $ input == 'safe' ) { $ this -> enableSafeMode ( ) ; } else { $ this -> disableSafeMode ( ) ; } }


public function addPath(string $path)
    {
        $path = \rtrim($path, '/');

        if (! \in_array($path, $this->paths)) {
            $this->paths[] = $path;
        }

        return $this;
    }

public function addPath ( string $ path ) { $ path = \ rtrim ( $ path , '/' ) ; if ( ! \ in_array ( $ path , $ this -> paths ) ) { $ this -> paths [ ] = $ path ; } return $ this ; }

Add a new path to finder.

@param  string  $path

@return $this


public function detect()
    {
        $extensions = [];
        $packages = $this->getComposerLockData();

        // Loop each path to check if there orchestra.json available within
        // the paths. We would only treat packages that include orchestra.json
        // as an Orchestra Platform extension.
        foreach ($this->paths as $key => $path) {
            $manifests = $this->files->glob($this->resolveExtensionPath("{$path}/orchestra.json"));

            // glob() method might return false if there an errors, convert
            // the result to an array.
            \is_array($manifests) || $manifests = [];

            foreach ($manifests as $manifest) {
                $name = \is_numeric($key)
                            ? $this->guessExtensionNameFromManifest($manifest, $path)
                            : $key;

                if (! \is_null($name)) {
                    $lockContent = $packages->firstWhere('name', $name);
                    $extensions[$name] = $this->getManifestContents($manifest, $lockContent);
                }
            }
        }

        return new Collection($extensions);
    }

Detect available extensions.

@return \Illuminate\Support\Collection


protected function getManifestContents(string $manifest, ?array $lockContent): array
    {
        $path = $sourcePath = $this->guessExtensionPath($manifest);
        $jsonable = \json_decode($this->files->get($manifest), true);

        // If json_decode fail, due to invalid json format. We going to
        // throw an exception so this error can be fixed by the developer
        // instead of allowing the application to run with a buggy config.
        if (\is_null($jsonable)) {
            throw new ManifestRuntimeException("Cannot decode file [{$manifest}]");
        }

        if (\is_array($lockContent)) {
            foreach (['description', 'version'] as $type) {
                $jsonable[$type] = $lockContent[$type] ?? $jsonable[$type] ?? null;
            }
        }

        $path = $jsonable['path'] ?? $path;

        $paths = [
            'path' => \rtrim($path, '/'),
            'source-path' => \rtrim($sourcePath, '/'),
        ];

        // Generate a proper manifest configuration for the extension. This
        // would allow other part of the application to use this configuration
        // to migrate, load service provider as well as preload some
        // configuration.
        return \array_merge($paths, $this->generateManifestConfig($jsonable));
    }

Get manifest contents.

@param  string  $manifest
@param  array|null  $lockContent

@throws \Orchestra\Contracts\Support\ManifestRuntimeException

@return array


protected function generateManifestConfig(array $config): array
    {
        // Assign extension manifest option or provide the default value.
        return Collection::make($this->manifestOptions)->mapWithKeys(function ($default, $key) use ($config) {
            return [$key => ($config[$key] ?? $default)];
        })->all();
    }

Generate a proper manifest configuration for the extension. This
would allow other part of the application to use this configuration
to migrate, load service provider as well as preload some
configuration.

@param  array  $config

@return array

Generate a proper manifest configuration for the extension . This would allow other part of the application to use this configuration to migrate load service provider as well as preload some configuration .


protected function getComposerLockData(): Collection
    {
        $json = [];

        if ($this->files->exists($this->config['path.composer'])) {
            $json = \json_decode($this->files->get($this->config['path.composer']), true);
        }

        return Collection::make($json['packages'] ?? []);
    }

protected function getComposerLockData ( ) : Collection { $ json = [ ] ; if ( $ this -> files -> exists ( $ this -> config [ 'path.composer' ] ) ) { $ json = \ json_decode ( $ this -> files -> get ( $ this -> config [ 'path.composer' ] ) , true ) ; } return Collection :: make ( $ json [ 'packages' ] ?? [ ] ) ; }

Get composer.lock data.

@return \Illuminate\Support\Collection


public function guessExtensionNameFromManifest(string $manifest, string $path): ?string
    {
        if (\rtrim($this->config['path.app'], '/') === \rtrim($path, '/')) {
            return 'app';
        }

        list($vendor, $package) = $namespace = $this->resolveExtensionNamespace($manifest);

        if (\is_null($vendor) && \is_null($package)) {
            return null;
        }

        // Each package should have vendor/package name pattern.
        $name = \trim(\implode('/', $namespace));

        return $this->validateExtensionName($name);
    }

Guess extension name from manifest.

@param  string  $manifest
@param  string  $path

@throws \RuntimeException

@return string|null


public function guessExtensionPath(string $path): string
    {
        $path = \str_replace('orchestra.json', '', $path);
        $app = \rtrim($this->config['path.app'], '/');
        $base = \rtrim($this->config['path.base'], '/');

        return \str_replace(
            ["{$app}/", "{$base}/vendor/", "{$base}/"],
            ['app::', 'vendor::', 'base::'],
            $path
        );
    }

public function guessExtensionPath ( string $ path ) : string { $ path = \ str_replace ( 'orchestra.json' , '' , $ path ) ; $ app = \ rtrim ( $ this -> config [ 'path.app' ] , '/' ) ; $ base = \ rtrim ( $ this -> config [ 'path.base' ] , '/' ) ; return \ str_replace ( [ "{$app}/" , "{$base}/vendor/" , "{$base}/" ] , [ 'app::' , 'vendor::' , 'base::' ] , $ path ) ; }

Guess extension path from manifest file.

@param  string  $path

@return string

Guess extension path from manifest file .


public function resolveExtensionNamespace(string $manifest): array
    {
        $vendor = null;
        $package = null;
        $manifest = \str_replace(['\\', '/'], DIRECTORY_SEPARATOR, $manifest);
        $fragment = \explode(DIRECTORY_SEPARATOR, $manifest);

        // Remove orchestra.json from fragment as we are only interested with
        // the two segment before it.
        if (\array_pop($fragment) == 'orchestra.json') {
            $package = \array_pop($fragment);
            $vendor = \array_pop($fragment);
        }

        return [$vendor, $package];
    }

Resolve extension namespace name from manifest.

@param  string  $manifest

@return array

Resolve extension namespace name from manifest .


public function validateExtensionName(string $name): string
    {
        if (\in_array($name, $this->reserved)) {
            throw new RuntimeException("Unable to register reserved name [{$name}] as extension.");
        }

        return $name;
    }

Validate extension name.

@param  string  $name

@throws \RuntimeException

@return string


public function registerViewFinder()
    {
        $this->app->bind('view.finder', function (Application $app) {
            $paths = $app->make('config')->get('view.paths', []);

            return new FileViewFinder($app->make('files'), $paths);
        });
    }

public function registerViewFinder ( ) { $ this -> app -> bind ( 'view.finder' , function ( Application $ app ) { $ paths = $ app -> make ( 'config' ) -> get ( 'view.paths' , [ ] ) ; return new FileViewFinder ( $ app -> make ( 'files' ) , $ paths ) ; } ) ; }

Register the service provider for view finder.

@return void

Register the service provider for view finder .


protected function registerTheme(): void
    {
        $this->app->singleton('orchestra.theme', function (Application $app) {
            return new ThemeManager($app);
        });

        $this->app->singleton('orchestra.theme.finder', function (Application $app) {
            return new Finder($app->make('files'), $app->publicPath());
        });
    }

protected function registerTheme ( ) : void { $ this -> app -> singleton ( 'orchestra.theme' , function ( Application $ app ) { return new ThemeManager ( $ app ) ; } ) ; $ this -> app -> singleton ( 'orchestra.theme.finder' , function ( Application $ app ) { return new Finder ( $ app -> make ( 'files' ) , $ app -> publicPath ( ) ) ; } ) ; }

Register the service provider for theme.

@return void

Register the service provider for theme .


public function detect(): Collection
    {
        $path = \rtrim($this->publicPath, '/').'/themes/';

        return Collection::make($this->files->directories($path))->mapWithKeys(function ($folder) {
            return [
                $this->parseThemeNameFromPath($folder) => new Manifest($this->files, \rtrim($folder, '/').'/'),
            ];
        });
    }

public function detect ( ) : Collection { $ path = \ rtrim ( $ this -> publicPath , '/' ) . '/themes/' ; return Collection :: make ( $ this -> files -> directories ( $ path ) ) -> mapWithKeys ( function ( $ folder ) { return [ $ this -> parseThemeNameFromPath ( $ folder ) => new Manifest ( $ this -> files , \ rtrim ( $ folder , '/' ) . '/' ) , ] ; } ) ; }

Detect available themes.

@throws \RuntimeException

@return \Illuminate\Support\Collection


protected function setCurrentTheme(Application $app, Theme $theme): void
    {
        $memory = $app->make('orchestra.memory')->makeOrFallback();
        $events = $app->make('events');

        // By default, we should consider all request to use "frontend"
        // theme and only convert to use "backend" routing when certain
        // event is fired.
        $theme->setTheme($memory->get('site.theme.frontend'));

        $events->listen('orchestra.started: admin', function () use ($theme, $memory) {
            $theme->setTheme($memory->get('site.theme.backend'));
        });

        $events->listen('composing: *', function () use ($theme) {
            $theme->boot();
        });
    }

Set current theme for request.

@param  \Illuminate\Contracts\Foundation\Application  $app
@param  \Orchestra\Contracts\Theme\Theme  $theme

@return void


protected function setThemeResolver(Application $app, Theme $theme): void
    {
        // The theme is only booted when the first view is being composed.
        // This would prevent multiple theme being booted in the same
        // request.
        if ($app->resolved('view')) {
            $theme->resolving();
        } else {
            $app->resolving('view', function () use ($theme) {
                $theme->resolving();
            });
        }
    }

Boot theme resolver.

@param  \Illuminate\Contracts\Foundation\Application  $app
@param  \Orchestra\Contracts\Theme\Theme  $theme

@return void


protected function registerExtension(): void
    {
        $this->app->singleton('orchestra.extension', function (Application $app) {
            $config = $app->make('config');
            $events = $app->make('events');
            $files = $app->make('files');
            $finder = $app->make('orchestra.extension.finder');
            $status = $app->make('orchestra.extension.status');
            $provider = $app->make('orchestra.extension.provider');

            return new Factory(
                $app, new Dispatcher($app, $config, $events, $files, $finder, $provider), $status
            );
        });
    }

protected function registerExtension ( ) : void { $ this -> app -> singleton ( 'orchestra.extension' , function ( Application $ app ) { $ config = $ app -> make ( 'config' ) ; $ events = $ app -> make ( 'events' ) ; $ files = $ app -> make ( 'files' ) ; $ finder = $ app -> make ( 'orchestra.extension.finder' ) ; $ status = $ app -> make ( 'orchestra.extension.status' ) ; $ provider = $ app -> make ( 'orchestra.extension.provider' ) ; return new Factory ( $ app , new Dispatcher ( $ app , $ config , $ events , $ files , $ finder , $ provider ) , $ status ) ; } ) ; }

Register the service provider for Extension.

@return void

Register the service provider for Extension .


protected function registerExtensionConfigManager(): void
    {
        $this->app->singleton('orchestra.extension.config', function (Application $app) {
            return new Config\Repository($app->make('config'), $app->make('orchestra.memory'));
        });
    }

protected function registerExtensionConfigManager ( ) : void { $ this -> app -> singleton ( 'orchestra.extension.config' , function ( Application $ app ) { return new Config \ Repository ( $ app -> make ( 'config' ) , $ app -> make ( 'orchestra.memory' ) ) ; } ) ; }

Register the service provider for Extension Config Manager.

@return void

Register the service provider for Extension Config Manager .


protected function registerExtensionFinder(): void
    {
        $this->app->singleton('orchestra.extension.finder', function (Application $app) {
            $config = [
                'path.app' => $app->path(),
                'path.base' => $app->basePath(),
                'path.composer' => $app->basePath('/composer.lock'),
            ];

            return new Finder($app->make('files'), $config);
        });
    }

protected function registerExtensionFinder ( ) : void { $ this -> app -> singleton ( 'orchestra.extension.finder' , function ( Application $ app ) { $ config = [ 'path.app' => $ app -> path ( ) , 'path.base' => $ app -> basePath ( ) , 'path.composer' => $ app -> basePath ( '/composer.lock' ) , ] ; return new Finder ( $ app -> make ( 'files' ) , $ config ) ; } ) ; }

Register the service provider for Extension Finder.

@return void

Register the service provider for Extension Finder .


protected function registerExtensionStatusChecker(): void
    {
        $this->app->singleton('orchestra.extension.status', function (Application $app) {
            return new StatusChecker($app->make('config'), $app->make('request'));
        });
    }

protected function registerExtensionStatusChecker ( ) : void { $ this -> app -> singleton ( 'orchestra.extension.status' , function ( Application $ app ) { return new StatusChecker ( $ app -> make ( 'config' ) , $ app -> make ( 'request' ) ) ; } ) ; }

Register the service provider for Extension Safe Mode Checker.

@return void

Register the service provider for Extension Safe Mode Checker .


protected function execute($listener, $type, Fluent $extension, Closure $callback)
    {
        $name = $extension->get('name');

        try {
            // Check if folder is writable via the web instance, this would
            // avoid issue running Orchestra Platform with debug as true where
            // creating/copying the directory would throw an ErrorException.
            if (! $this->factory->permission($name)) {
                throw new FilePermissionException("[{$name}] is not writable.");
            }

            $callback($this->factory, $name);
        } catch (FilePermissionException $e) {
            return $listener->{"{$type}HasFailed"}($extension, ['error' => $e->getMessage()]);
        }

        return $listener->{"{$type}HasSucceed"}($extension);
    }

Execute extension processing.

@param  object  $listener
@param  string  $type
@param  \Illuminate\Support\Fluent  $extension
@param  \Closure  $callback

@return mixed


protected function getScheme(?bool $secure): string
    {
        if (\is_null($secure)) {
            return $this->forceSchema ?: $this->request->getScheme().'://';
        }

        return $secure ? 'https://' : 'http://';
    }

protected function getScheme ( ? bool $ secure ) : string { if ( \ is_null ( $ secure ) ) { return $ this -> forceSchema ? : $ this -> request -> getScheme ( ) . '://' ; } return $ secure ? 'https://' : 'http://' ; }

Get the scheme for a raw URL.

@param  bool|null  $secure

@return string


public function handle(string $handles)
    {
        // If the handles doesn't start as "//some.domain.com/foo" we should
        // assume that it doesn't belong to any subdomain, otherwise we
        // need to split the value to "some.domain.com" and "foo".
        if (\is_null($handles) || ! Str::startsWith($handles, ['//', 'http://', 'https://'])) {
            $this->prefix = $handles;
        } else {
            $handles = \substr(\str_replace(['http://', 'https://'], '//', $handles), 2);
            $fragments = \explode('/', $handles, 2);
            $this->domain = \array_shift($fragments);
            $this->prefix = \array_shift($fragments);
        }

        // It is possible that prefix would be null, in this case assume
        // it handle the main path under the domain.
        ! \is_null($this->prefix) || $this->prefix = '/';

        return $this;
    }

Build route.

@param  string  $handles

@return $this


public function domain(bool $forceBase = false): ?string
    {
        $pattern = $this->domain;
        $baseUrl = $this->getBaseUrl();

        if (\is_null($pattern) && $forceBase === true) {
            $pattern = $baseUrl;
        } elseif (Str::contains($pattern, '{{domain}}')) {
            $pattern = \str_replace('{{domain}}', $baseUrl, $pattern);
        }

        return $pattern;
    }

public function domain ( bool $ forceBase = false ) : ? string { $ pattern = $ this -> domain ; $ baseUrl = $ this -> getBaseUrl ( ) ; if ( \ is_null ( $ pattern ) && $ forceBase === true ) { $ pattern = $ baseUrl ; } elseif ( Str :: contains ( $ pattern , '{{domain}}' ) ) { $ pattern = \ str_replace ( '{{domain}}' , $ baseUrl , $ pattern ) ; } return $ pattern ; }

Get route domain.

@param  bool  $forceBase

@return string|null


public function group(bool $forceBase = false): array
    {
        $group = [
            'prefix' => $this->prefix($forceBase),
        ];

        if (! \is_null($domain = $this->domain($forceBase))) {
            $group['domain'] = $domain;
        }

        return $group;
    }

public function group ( bool $ forceBase = false ) : array { $ group = [ 'prefix' => $ this -> prefix ( $ forceBase ) , ] ; if ( ! \ is_null ( $ domain = $ this -> domain ( $ forceBase ) ) ) { $ group [ 'domain' ] = $ domain ; } return $ group ; }

Get route group.

@param  bool  $forceBase

@return array


public function is(string $pattern): bool
    {
        $path = $this->path();
        $prefix = $this->prefix();

        foreach (\func_get_args() as $pattern) {
            $pattern = ($pattern === '*' ? "{$prefix}*" : "{$prefix}/{$pattern}");
            $pattern = \trim($pattern, '/');

            empty($pattern) && $pattern = '/';

            if (Str::is($pattern, $path)) {
                return true;
            }
        }

        return false;
    }

public function is ( string $ pattern ) : bool { $ path = $ this -> path ( ) ; $ prefix = $ this -> prefix ( ) ; foreach ( \ func_get_args ( ) as $ pattern ) { $ pattern = ( $ pattern === '*' ? "{$prefix}*" : "{$prefix}/{$pattern}" ) ; $ pattern = \ trim ( $ pattern , '/' ) ; empty ( $ pattern ) && $ pattern = '/' ; if ( Str :: is ( $ pattern , $ path ) ) { return true ; } } return false ; }

Determine if the current request URI matches a pattern.

@param  string  $pattern

@return bool

Determine if the current request URI matches a pattern .


public function prefix(bool $forceBase = false): string
    {
        $pattern = \trim($this->prefix, '/');

        if (\is_null($this->domain) && $forceBase === true) {
            $pattern = \trim($this->basePrefix, '/')."/{$pattern}";
            $pattern = \trim($pattern, '/');
        }

        empty($pattern) && $pattern = '/';

        return $pattern;
    }

public function prefix ( bool $ forceBase = false ) : string { $ pattern = \ trim ( $ this -> prefix , '/' ) ; if ( \ is_null ( $ this -> domain ) && $ forceBase === true ) { $ pattern = \ trim ( $ this -> basePrefix , '/' ) . "/{$pattern}" ; $ pattern = \ trim ( $ pattern , '/' ) ; } empty ( $ pattern ) && $ pattern = '/' ; return $ pattern ; }

Get route prefix.

@param  bool  $forceBase

@return string


public function root(): string
    {
        $scheme = $this->getScheme(null);
        $domain = \trim($this->domain(true), '/');
        $prefix = $this->prefix(true);

        return \trim("{$scheme}{$domain}/{$prefix}", '/');
    }

public function root ( ) : string { $ scheme = $ this -> getScheme ( null ) ; $ domain = \ trim ( $ this -> domain ( true ) , '/' ) ; $ prefix = $ this -> prefix ( true ) ; return \ trim ( "{$scheme}{$domain}/{$prefix}" , '/' ) ; }


public function getBaseUrl(): string
    {
        if (\is_null($this->baseUrl)) {
            $this->resolveBaseUrlFrom($this->request->root());
        }

        return $this->baseUrl;
    }

public function getBaseUrl ( ) : string { if ( \ is_null ( $ this -> baseUrl ) ) { $ this -> resolveBaseUrlFrom ( $ this -> request -> root ( ) ) ; } return $ this -> baseUrl ; }


protected function resolveBaseUrlFrom(?string $root): void
    {
        // Build base URL and prefix.
        $baseUrl = \ltrim(\str_replace(['https://', 'http://'], '', $root), '/');
        $base = \explode('/', $baseUrl, 2);

        if (\count($base) > 1) {
            $this->basePrefix = \array_pop($base);
        }

        $this->baseUrl = \array_shift($base);
    }

protected
function
resolveBaseUrlFrom
(
string
$
root
)
:
void
{
// Build base URL and prefix.
$
baseUrl
=
\
ltrim
(
\
str_replace
(
[
'https://'
,
'http://'
]
,
''
,
$
root
)
,
'/'
)
;
$
base
=
\
explode
(
'/'
,
$
baseUrl
,
2
)
;
if
(
\
count
(
$
base
)
>
1
)
{
$
this
->
basePrefix
=
\
array_pop
(
$
base
)
;
}
$
this
->
baseUrl
=
\
array_shift
(
$
base
)
;
}

Resolve base url from given path.

@param  string|null  $root

@return void


public static function safeParse($input, $validateDuplicateKeys = true)
    {
        if (method_exists('Symfony\Component\Yaml\Yaml', 'setPhpParsing')) {
            Yaml::setPhpParsing(false);
        }

        if ($validateDuplicateKeys) {
            self::validateDuplicatedKey($input);
        }

        return (new Parser())->parse($input, true, false);
    }

public static function safeParse ( $ input , $ validateDuplicateKeys = true ) { if ( method_exists ( 'Symfony\Component\Yaml\Yaml' , 'setPhpParsing' ) ) { Yaml :: setPhpParsing ( false ) ; } if ( $ validateDuplicateKeys ) { self :: validateDuplicatedKey ( $ input ) ; } return ( new Parser ( ) ) -> parse ( $ input , true , false ) ; }

Safely parses the input string.

In contrast to the original Yaml class, we do not try to resolve the input to a filename first. Consequentially,
there is no need to sanitize the input prior to calling this method.

@param string $input

@return mixed


private static function validateDuplicatedKey($input)
    {
        $lines = explode("\n", $input);
        $data = array();
        $nbSpacesOfLastLine = 0;

        foreach ($lines as $linenumber => $line) {
            $trimmedLine = ltrim($line, ' ');
            if ($trimmedLine === '' || $trimmedLine[0] === '#') {
                continue;
            }

            $nbSpacesOfCurrentLine = strlen($line) - strlen($trimmedLine);

            if ($nbSpacesOfCurrentLine < $nbSpacesOfLastLine) {
                foreach ($data as $nbSpaces => $keys) {
                    if ($nbSpaces > $nbSpacesOfCurrentLine) {
                        unset($data[$nbSpaces]);
                    }
                }
            }

            if ($trimmedLine[0] === '-' || false === $pos = strpos($trimmedLine, ':')) {
                continue;
            }

            $key = substr($trimmedLine, 0, $pos);

            if (isset($data[$nbSpacesOfCurrentLine][$key])) {
                throw new ParseException(sprintf('Duplicate key "%s" detected on line %s whilst parsing YAML.', $key, $linenumber));
            }

            $data[$nbSpacesOfCurrentLine][$key] = array();
            $nbSpacesOfLastLine = $nbSpacesOfCurrentLine;
        }
    }

Validate if there is duplicated keys in the input yml string

@param string $input
@return bool


public function activating(string $name, array $options): void
    {
        $this->register($name, $options);

        $this->fireEvent($name, $options, 'activating');

        $this->provider->writeFreshManifest();
    }

public function activating ( string $ name , array $ options ) : void { $ this -> register ( $ name , $ options ) ; $ this -> fireEvent ( $ name , $ options , 'activating' ) ; $ this -> provider -> writeFreshManifest ( ) ; }

Activating the extension.

@param  string  $name
@param  array   $options

@return void


public function deactivating(string $name, array $options): void
    {
        $this->fireEvent($name, $options, 'deactivating');

        $this->provider->writeFreshManifest();
    }

public function deactivating ( string $ name , array $ options ) : void { $ this -> fireEvent ( $ name , $ options , 'deactivating' ) ; $ this -> provider -> writeFreshManifest ( ) ; }

Deactivating the extension.

@param  string  $name
@param  array   $options

@return void


protected function registerExtensionProviders(array $options): void
    {
        $services = $options['provides'] ?? [];

        ! empty($services) && $this->provider->provides($services);
    }

protected function registerExtensionProviders ( array $ options ) : void { $ services = $ options [ 'provides' ] ?? [ ] ; ! empty ( $ services ) && $ this -> provider -> provides ( $ services ) ; }

Register extension service providers.

@param  array  $options

@return void


protected function registerExtensionPlugin(array $options): void
    {
        $plugin = $options['plugin'] ?? null;

        ! \is_null($plugin) && $this->app->make($plugin)->bootstrap($this->app);
    }

protected function registerExtensionPlugin ( array $ options ) : void { $ plugin = $ options [ 'plugin' ] ?? null ; ! \ is_null ( $ plugin ) && $ this -> app -> make ( $ plugin ) -> bootstrap ( $ this -> app ) ; }

Register extension plugin.

@param  array  $options

@return void


public function boot(): void
    {
        foreach ($this->extensions as $name => $options) {
            $this->fireEvent($name, $options, 'booted');
        }

        $this->provider->writeManifest();
    }

public function boot ( ) : void { foreach ( $ this -> extensions as $ name => $ options ) { $ this -> fireEvent ( $ name , $ options , 'booted' ) ; } $ this -> provider -> writeManifest ( ) ; }


public function start(string $name, array $options): void
    {
        $basePath = \rtrim($options['path'], '/');
        $sourcePath = \rtrim($options['source-path'] ?? $basePath, '/');

        $search = ['source-path::', 'app::/'];
        $replacement = ["{$sourcePath}/", 'app::'];

        // By now, extension should already exist as an extension. We should
        // be able start orchestra.php start file on each package.
        $this->getAutoloadFiles(Collection::make($options['autoload'] ?? []))
            ->each(function ($path) use ($search, $replacement) {
                $this->loadAutoloaderFile(\str_replace($search, $replacement, $path));
            });

        $this->fireEvent($name, $options, 'started');
    }

Start the extension.

@param  string  $name
@param  array   $options

@return void


protected function fireEvent(string $name, array $options, string $type = 'started'): void
    {
        $this->dispatcher->dispatch("extension.{$type}", [$name, $options]);
        $this->dispatcher->dispatch("extension.{$type}: {$name}", [$options]);
    }

protected
function
fireEvent
(
string
$
name
,
array
$
options
,
string
$
type
=
'started'
)
:
void
{
$
this
->
dispatcher
->
dispatch
(
"extension.{$type}"
,
[
$
name
,
$
options
]
)
;
$
this
->
dispatcher
->
dispatch
(
"extension.{$type}: {$name}"
,
[
$
options
]
)
;
}

Fire events.

@param  string  $name
@param  array   $options
@param  string  $type

@return void


protected function getAutoloadFiles(Collection $autoload): Collection
    {
        return $autoload->map(function ($path) {
            return Str::contains($path, '::') ? $path : 'source-path::'.\ltrim($path, '/');
        })->merge(['source-path::src/orchestra.php', 'source-path::orchestra.php']);
    }

protected function getAutoloadFiles ( Collection $ autoload ) : Collection { return $ autoload -> map ( function ( $ path ) { return Str :: contains ( $ path , '::' ) ? $ path : 'source-path::' . \ ltrim ( $ path , '/' ) ; } ) -> merge ( [ 'source-path::src/orchestra.php' , 'source-path::orchestra.php' ] ) ; }

Get list of available paths for the extension.

@param  array  $autoload

@return \Illuminate\Support\Collection

Get list of available paths for the extension .


protected function loadAutoloaderFile(string $filePath): void
    {
        $filePath = $this->finder->resolveExtensionPath($filePath);

        if ($this->files->isFile($filePath)) {
            $this->files->getRequire($filePath);
        }
    }

protected function loadAutoloaderFile ( string $ filePath ) : void { $ filePath = $ this -> finder -> resolveExtensionPath ( $ filePath ) ; if ( $ this -> files -> isFile ( $ filePath ) ) { $ this -> files -> getRequire ( $ filePath ) ; } }

Load autoloader file.

@param  string  $filePath

@return void