PageRenderTime 47ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/CMS/src/Core/Package/PackageFactory.php

http://github.com/QuickAppsCMS/QuickApps-CMS
PHP | 224 lines | 83 code | 20 blank | 121 comment | 7 complexity | 0a058f143818931926ddb57bf8aac06f MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. <?php
  2. /**
  3. * Licensed under The GPL-3.0 License
  4. * For full copyright and license information, please see the LICENSE.txt
  5. * Redistributions of files must retain the above copyright notice.
  6. *
  7. * @since 2.0.0
  8. * @author Christopher Castro <chris@quickapps.es>
  9. * @link http://www.quickappscms.org
  10. * @license http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
  11. */
  12. namespace CMS\Core\Package;
  13. use CMS\Core\Package\BasePackage;
  14. use CMS\Core\Package\GenericPackage;
  15. use CMS\Core\Package\LibraryPackage;
  16. use CMS\Core\Package\PluginPackage;
  17. use CMS\Core\Package\ThirdPartyPackage;
  18. use CMS\Core\Plugin;
  19. /**
  20. * Used to create package objects.
  21. *
  22. * In QuickAppsCMS plugins and themes are internally handled as "packages",
  23. * there exists a few packages types, for example third-party libraries which are
  24. * installed through composer's install command. Each package type is represented
  25. * by its own class, QuickAppsCMS comes with a few of this classes: `PluginPackage`,
  26. * `LibraryPackage`, `ThirdPartyPackage` and `GenericPackage`. These classes
  27. * provides a set of useful methods for interacting with QuickAppsCMS.
  28. *
  29. * This class automatically tries to determinate the best package type based on
  30. * its name using what we call "detectors" methods. This class comes with a few
  31. * built-in detector methods which are described below, however more detectors can
  32. * be registered (or overwrite existing ones) using the `addDetector()` method. A
  33. * "detector" is a simple callable function which based on a given package name it
  34. * should return an object representing that package if the given package name
  35. * matches the type of package the detector represents. For example:
  36. *
  37. *
  38. * ### Registering detectors:
  39. *
  40. * ```php
  41. * PackageFactory::addDetector('myVendorPlugin', function ($packageName) {
  42. * list($vendor, $package) = packageSplit($packageName);
  43. * if ($vendor == 'my-vendor-plugin') {
  44. * return new MyVendorPackage($package, "/path/to/{$package}/")
  45. * }
  46. * });
  47. * ```
  48. *
  49. * In this example we are using our own `MyVendorPackage` class for representing
  50. * packages created by `my-vendor-plugin`.
  51. *
  52. * ### Built-in detectors:
  53. *
  54. * - plugin: For packages representing QuickAppsCMS plugins.
  55. *
  56. * - library: For packages representing PHP extension libraries or PHP itself, for
  57. * example: `ext-intl`, `php`, `ext-zlib`, etc
  58. *
  59. * - thirdParty: For packages representing third-party libraries installed using
  60. * composer, for example: `nesbot/carbon`, `robmorgan/phinx`, etc.
  61. *
  62. * ### Detection order:
  63. *
  64. * Detectors methods are invoked in the order they were registered, if one detector
  65. * fails to detect a package the next registered detector will be used, and so on.
  66. * By default `GenricPackage` will be used if all detectors fails to detect the
  67. * given package name.
  68. */
  69. class PackageFactory
  70. {
  71. /**
  72. * List of detectors methods indexed as `name` => `callable`.
  73. *
  74. * @var array
  75. */
  76. protected static $_detectors = [];
  77. /**
  78. * Indicates if default detectors were initialized.
  79. *
  80. * @var bool
  81. */
  82. protected static $_initialized = false;
  83. /**
  84. * Given a full package name, returns an instance of an object representing
  85. * that package.
  86. *
  87. * If no matching package is found, `GenericPackage` will be used by default.
  88. *
  89. * @param string $package Full package name. e.g. `vendor-name/package-name`
  90. * @return \CMS\Core\Package\BasePackage
  91. */
  92. public static function create($package)
  93. {
  94. static::_init();
  95. foreach (static::$_detectors as $name => $callable) {
  96. $result = $callable($package);
  97. if ($result instanceof BasePackage) {
  98. return $result;
  99. }
  100. }
  101. return new GenericPackage($package, '', '');
  102. }
  103. /**
  104. * Initializes this class.
  105. *
  106. * @return void
  107. */
  108. protected static function _init()
  109. {
  110. if (static::$_initialized) {
  111. return;
  112. }
  113. static::$_detectors['plugin'] = function ($package) {
  114. return static::_getPlugin($package);
  115. };
  116. static::$_detectors['library'] = function ($package) {
  117. return static::_getLibrary($package);
  118. };
  119. static::$_detectors['thirdParty'] = function ($package) {
  120. return static::_getThirdParty($package);
  121. };
  122. static::$_initialized = true;
  123. }
  124. /**
  125. * Registers a new package detection method.
  126. *
  127. * Callable function should return an object package extending
  128. * `QuickApp\Core\Package\BasePackage` class on success.
  129. *
  130. * @param string $name The name for this detector
  131. * @param callable $method The callable method
  132. * @return void
  133. */
  134. public static function addDetector($name, callable $method)
  135. {
  136. static::$_detectors[$name] = $method;
  137. }
  138. /**
  139. * Gets a list of all registered detectors.
  140. *
  141. * @return array
  142. */
  143. public static function detectors()
  144. {
  145. return static::$_detectors;
  146. }
  147. /**
  148. * Tries to get a QuickAppsCMS plugin.
  149. *
  150. * @param string $package Full package name
  151. * @return bool|\CMS\Core\Package\PluginPackage
  152. */
  153. protected static function _getPlugin($package)
  154. {
  155. list(, $plugin) = packageSplit($package, true);
  156. if (Plugin::exists($plugin)) {
  157. return new PluginPackage(
  158. quickapps("plugins.{$plugin}.name"),
  159. quickapps("plugins.{$plugin}.path")
  160. );
  161. }
  162. return false;
  163. }
  164. /**
  165. * Tries to get package that represents a PHP library.
  166. *
  167. * @param string $package Full package name
  168. * @return bool|\CMS\Core\Package\LibraryPackage
  169. */
  170. protected static function _getLibrary($package)
  171. {
  172. if (strpos($package, '/') === false) {
  173. return new LibraryPackage($package, null);
  174. }
  175. return false;
  176. }
  177. /**
  178. * Tries to get package that represents a third party library.
  179. *
  180. * - Package must exists on `VENDOR_PATH/vendor-name/package-name/`.
  181. * - Its composer.json file must exists as well.
  182. * - Package must be registered on Composer's "installed.json" file.
  183. *
  184. * @param string $package Full package name
  185. * @return bool|\CMS\Core\Package\ThirdPartyPackage
  186. */
  187. protected static function _getThirdParty($package)
  188. {
  189. list($vendor, $packageName) = packageSplit($package);
  190. $packageJson = normalizePath(VENDOR_INCLUDE_PATH . "/{$vendor}/{$packageName}/composer.json");
  191. if (is_readable($packageJson)) {
  192. $installedJson = normalizePath(VENDOR_INCLUDE_PATH . "composer/installed.json");
  193. if (is_readable($installedJson)) {
  194. $json = (array)json_decode(file_get_contents($installedJson), true);
  195. foreach ($json as $pkg) {
  196. if (strtolower($pkg['name']) === strtolower($package)) {
  197. return new ThirdPartyPackage($package, dirname($packageJson), $pkg['version']);
  198. }
  199. }
  200. }
  201. }
  202. return false;
  203. }
  204. }