399 lines
12 KiB
PHP
399 lines
12 KiB
PHP
<?php
|
|
namespace Grav\Common\GPM;
|
|
|
|
use Grav\Common\Inflector;
|
|
use Grav\Common\Iterator;
|
|
use Grav\Common\Utils;
|
|
|
|
class GPM extends Iterator
|
|
{
|
|
/**
|
|
* Local installed Packages
|
|
* @var Local\Packages
|
|
*/
|
|
private $installed;
|
|
|
|
/**
|
|
* Remote available Packages
|
|
* @var Remote\Packages
|
|
*/
|
|
private $repository;
|
|
|
|
/**
|
|
* @var Remote\Grav
|
|
*/
|
|
public $grav;
|
|
|
|
/**
|
|
* Internal cache
|
|
* @var
|
|
*/
|
|
protected $cache;
|
|
|
|
protected $install_paths = ['plugins' => 'user/plugins/%name%', 'themes' => 'user/themes/%name%', 'skeletons' => 'user/'];
|
|
|
|
/**
|
|
* Creates a new GPM instance with Local and Remote packages available
|
|
* @param boolean $refresh Applies to Remote Packages only and forces a refetch of data
|
|
* @param callable $callback Either a function or callback in array notation
|
|
*/
|
|
public function __construct($refresh = false, $callback = null)
|
|
{
|
|
$this->installed = new Local\Packages();
|
|
try {
|
|
$this->repository = new Remote\Packages($refresh, $callback);
|
|
$this->grav = new Remote\Grav($refresh, $callback);
|
|
} catch (\Exception $e) {
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the Locally installed packages
|
|
* @return Iterator The installed packages
|
|
*/
|
|
public function getInstalled()
|
|
{
|
|
return $this->installed;
|
|
}
|
|
|
|
/**
|
|
* Returns the amount of locally installed packages
|
|
* @return integer Amount of installed packages
|
|
*/
|
|
public function countInstalled()
|
|
{
|
|
$installed = $this->getInstalled();
|
|
|
|
return count($installed['plugins']) + count($installed['themes']);
|
|
}
|
|
|
|
/**
|
|
* Return the instance of a specific Plugin
|
|
* @param string $slug The slug of the Plugin
|
|
* @return Local\Package The instance of the Plugin
|
|
*/
|
|
public function getInstalledPlugin($slug)
|
|
{
|
|
return $this->installed['plugins'][$slug];
|
|
}
|
|
|
|
/**
|
|
* Returns the Locally installed plugins
|
|
* @return Iterator The installed plugins
|
|
*/
|
|
public function getInstalledPlugins()
|
|
{
|
|
return $this->installed['plugins'];
|
|
}
|
|
|
|
/**
|
|
* Checks if a Plugin is installed
|
|
* @param string $slug The slug of the Plugin
|
|
* @return boolean True if the Plugin has been installed. False otherwise
|
|
*/
|
|
public function isPluginInstalled($slug)
|
|
{
|
|
return isset($this->installed['plugins'][$slug]);
|
|
}
|
|
|
|
/**
|
|
* Return the instance of a specific Theme
|
|
* @param string $slug The slug of the Theme
|
|
* @return Local\Package The instance of the Theme
|
|
*/
|
|
public function getInstalledTheme($slug)
|
|
{
|
|
return $this->installed['themes'][$slug];
|
|
}
|
|
|
|
/**
|
|
* Returns the Locally installed themes
|
|
* @return Iterator The installed themes
|
|
*/
|
|
public function getInstalledThemes()
|
|
{
|
|
return $this->installed['themes'];
|
|
}
|
|
|
|
/**
|
|
* Checks if a Theme is installed
|
|
* @param string $slug The slug of the Theme
|
|
* @return boolean True if the Theme has been installed. False otherwise
|
|
*/
|
|
public function isThemeInstalled($slug)
|
|
{
|
|
return isset($this->installed['themes'][$slug]);
|
|
}
|
|
|
|
/**
|
|
* Returns the amount of updates available
|
|
* @return integer Amount of available updates
|
|
*/
|
|
public function countUpdates()
|
|
{
|
|
$count = 0;
|
|
|
|
$count += count($this->getUpdatablePlugins());
|
|
$count += count($this->getUpdatableThemes());
|
|
|
|
return $count;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of Plugins and Themes that can be updated.
|
|
* Plugins and Themes are extended with the `available` property that relies to the remote version
|
|
* @return array Array of updatable Plugins and Themes.
|
|
* Format: ['total' => int, 'plugins' => array, 'themes' => array]
|
|
*/
|
|
public function getUpdatable()
|
|
{
|
|
$plugins = $this->getUpdatablePlugins();
|
|
$themes = $this->getUpdatableThemes();
|
|
|
|
$items = [
|
|
'total' => count($plugins)+count($themes),
|
|
'plugins' => $plugins,
|
|
'themes' => $themes
|
|
];
|
|
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of Plugins that can be updated.
|
|
* The Plugins are extended with the `available` property that relies to the remote version
|
|
* @return Iterator Array of updatable Plugins
|
|
*/
|
|
public function getUpdatablePlugins()
|
|
{
|
|
$items = [];
|
|
$repository = $this->repository['plugins'];
|
|
|
|
// local cache to speed things up
|
|
if (isset($this->cache[__METHOD__])) {
|
|
return $this->cache[__METHOD__];
|
|
}
|
|
|
|
foreach ($this->installed['plugins'] as $slug => $plugin) {
|
|
if (!isset($repository[$slug]) || $plugin->symlink) {
|
|
continue;
|
|
}
|
|
|
|
$local_version = $plugin->version ? $plugin->version : 'Unknown';
|
|
$remote_version = $repository[$slug]->version;
|
|
|
|
if (version_compare($local_version, $remote_version) < 0) {
|
|
$repository[$slug]->available = $remote_version;
|
|
$repository[$slug]->version = $local_version;
|
|
$items[$slug] = $repository[$slug];
|
|
}
|
|
}
|
|
|
|
$this->cache[__METHOD__] = $items;
|
|
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Check if a Plugin or Theme is updatable
|
|
* @param string $slug The slug of the package
|
|
* @return boolean True if updatable. False otherwise or if not found
|
|
*/
|
|
public function isUpdatable($slug)
|
|
{
|
|
return $this->isPluginUpdatable($slug) || $this->isThemeUpdatable($slug);
|
|
}
|
|
|
|
/**
|
|
* Checks if a Plugin is updatable
|
|
* @param string $plugin The slug of the Plugin
|
|
* @return boolean True if the Plugin is updatable. False otherwise
|
|
*/
|
|
public function isPluginUpdatable($plugin)
|
|
{
|
|
return array_key_exists($plugin, (array) $this->getUpdatablePlugins());
|
|
}
|
|
|
|
/**
|
|
* Returns an array of Themes that can be updated.
|
|
* The Themes are extended with the `available` property that relies to the remote version
|
|
* @return Iterator Array of updatable Themes
|
|
*/
|
|
public function getUpdatableThemes()
|
|
{
|
|
$items = [];
|
|
$repository = $this->repository['themes'];
|
|
|
|
// local cache to speed things up
|
|
if (isset($this->cache[__METHOD__])) {
|
|
return $this->cache[__METHOD__];
|
|
}
|
|
|
|
foreach ($this->installed['themes'] as $slug => $plugin) {
|
|
if (!isset($repository[$slug]) || $plugin->symlink) {
|
|
continue;
|
|
}
|
|
|
|
$local_version = $plugin->version ? $plugin->version : 'Unknown';
|
|
$remote_version = $repository[$slug]->version;
|
|
|
|
if (version_compare($local_version, $remote_version) < 0) {
|
|
$repository[$slug]->available = $remote_version;
|
|
$repository[$slug]->version = $local_version;
|
|
$items[$slug] = $repository[$slug];
|
|
}
|
|
}
|
|
|
|
$this->cache[__METHOD__] = $items;
|
|
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* Checks if a Theme is Updatable
|
|
* @param string $theme The slug of the Theme
|
|
* @return boolean True if the Theme is updatable. False otherwise
|
|
*/
|
|
public function isThemeUpdatable($theme)
|
|
{
|
|
return array_key_exists($theme, (array) $this->getUpdatableThemes());
|
|
}
|
|
|
|
/**
|
|
* Returns a Plugin from the repository
|
|
* @param string $slug The slug of the Plugin
|
|
* @return mixed Package if found, NULL if not
|
|
*/
|
|
public function getRepositoryPlugin($slug)
|
|
{
|
|
return @$this->repository['plugins'][$slug];
|
|
}
|
|
|
|
/**
|
|
* Returns the list of Plugins available in the repository
|
|
* @return Iterator The Plugins remotely available
|
|
*/
|
|
public function getRepositoryPlugins()
|
|
{
|
|
return $this->repository['plugins'];
|
|
}
|
|
|
|
/**
|
|
* Returns a Theme from the repository
|
|
* @param string $slug The slug of the Theme
|
|
* @return mixed Package if found, NULL if not
|
|
*/
|
|
public function getRepositoryTheme($slug)
|
|
{
|
|
return @$this->repository['themes'][$slug];
|
|
}
|
|
|
|
/**
|
|
* Returns the list of Themes available in the repository
|
|
* @return Iterator The Themes remotely available
|
|
*/
|
|
public function getRepositoryThemes()
|
|
{
|
|
return $this->repository['themes'];
|
|
}
|
|
|
|
/**
|
|
* Returns the list of Plugins and Themes available in the repository
|
|
* @return array Array of available Plugins and Themes
|
|
* Format: ['plugins' => array, 'themes' => array]
|
|
*/
|
|
public function getRepository()
|
|
{
|
|
return $this->repository;
|
|
}
|
|
|
|
/**
|
|
* Searches for a Package in the repository
|
|
* @param string $search Can be either the slug or the name
|
|
* @return Remote\Package Package if found, FALSE if not
|
|
*/
|
|
public function findPackage($search)
|
|
{
|
|
$search = strtolower($search);
|
|
if ($found = $this->getRepositoryTheme($search)) {
|
|
return $found;
|
|
}
|
|
|
|
if ($found = $this->getRepositoryPlugin($search)) {
|
|
return $found;
|
|
}
|
|
|
|
foreach ($this->getRepositoryThemes() as $slug => $theme) {
|
|
if ($search == $slug || $search == $theme->name) {
|
|
return $theme;
|
|
}
|
|
}
|
|
|
|
foreach ($this->getRepositoryPlugins() as $slug => $plugin) {
|
|
if ($search == $slug || $search == $plugin->name) {
|
|
return $plugin;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Returns the list of Plugins and Themes available in the repository
|
|
* @return array Array of available Plugins and Themes
|
|
* Format: ['plugins' => array, 'themes' => array]
|
|
*/
|
|
/**
|
|
* Searches for a list of Packages in the repository
|
|
* @param array $searches An array of either slugs or names
|
|
* @return array Array of found Packages
|
|
* Format: ['total' => int, 'not_found' => array, <found-slugs>]
|
|
*/
|
|
public function findPackages($searches = [])
|
|
{
|
|
$packages = ['total' => 0, 'not_found' => []];
|
|
$inflector = new Inflector();
|
|
|
|
foreach ($searches as $search) {
|
|
$repository = '';
|
|
// if this is an object, get the search data from the key
|
|
if (is_object($search)) {
|
|
$search = (array) $search;
|
|
$key = key($search);
|
|
$repository = $search[$key];
|
|
$search = $key;
|
|
}
|
|
|
|
if ($found = $this->findPackage($search)) {
|
|
// set override repository if provided
|
|
if ($repository) {
|
|
$found->override_repository = $repository;
|
|
}
|
|
if (!isset($packages[$found->package_type])) {
|
|
$packages[$found->package_type] = [];
|
|
}
|
|
|
|
$packages[$found->package_type][$found->slug] = $found;
|
|
$packages['total']++;
|
|
} else {
|
|
// make a best guess at the type based on the repo URL
|
|
if (Utils::contains($repository, '-theme')) {
|
|
$type = 'themes';
|
|
} else {
|
|
$type = 'plugins';
|
|
}
|
|
|
|
$not_found = new \stdClass();
|
|
$not_found->name = $inflector->camelize($search);
|
|
$not_found->slug = $search;
|
|
$not_found->package_type = $type;
|
|
$not_found->install_path = str_replace('%name%', $search, $this->install_paths[$type]);
|
|
$not_found->override_repository = $repository;
|
|
$packages['not_found'][$search] = $not_found;
|
|
}
|
|
}
|
|
|
|
return $packages;
|
|
}
|
|
}
|