puli /
manager
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | /* |
||
| 4 | * This file is part of the puli/manager package. |
||
| 5 | * |
||
| 6 | * (c) Bernhard Schussek <[email protected]> |
||
| 7 | * |
||
| 8 | * For the full copyright and license information, please view the LICENSE |
||
| 9 | * file that was distributed with this source code. |
||
| 10 | */ |
||
| 11 | |||
| 12 | namespace Puli\Manager\Api; |
||
| 13 | |||
| 14 | use LogicException; |
||
| 15 | use Psr\Log\LoggerInterface; |
||
| 16 | use Puli\Discovery\Api\Discovery; |
||
| 17 | use Puli\Discovery\Api\EditableDiscovery; |
||
| 18 | use Puli\Manager\Api\Asset\AssetManager; |
||
| 19 | use Puli\Manager\Api\Cache\CacheFileSerializer; |
||
| 20 | use Puli\Manager\Api\Cache\CacheManager; |
||
| 21 | use Puli\Manager\Api\Config\Config; |
||
| 22 | use Puli\Manager\Api\Config\ConfigFileManager; |
||
| 23 | use Puli\Manager\Api\Config\ConfigFileSerializer; |
||
| 24 | use Puli\Manager\Api\Context\Context; |
||
| 25 | use Puli\Manager\Api\Context\ProjectContext; |
||
| 26 | use Puli\Manager\Api\Discovery\DiscoveryManager; |
||
| 27 | use Puli\Manager\Api\Factory\FactoryManager; |
||
| 28 | use Puli\Manager\Api\Installation\InstallationManager; |
||
| 29 | use Puli\Manager\Api\Installer\InstallerManager; |
||
| 30 | use Puli\Manager\Api\Package\PackageFileSerializer; |
||
| 31 | use Puli\Manager\Api\Package\PackageManager; |
||
| 32 | use Puli\Manager\Api\Package\RootPackageFile; |
||
| 33 | use Puli\Manager\Api\Package\RootPackageFileManager; |
||
| 34 | use Puli\Manager\Api\Repository\RepositoryManager; |
||
| 35 | use Puli\Manager\Api\Server\ServerManager; |
||
| 36 | use Puli\Manager\Api\Storage\Storage; |
||
| 37 | use Puli\Manager\Assert\Assert; |
||
| 38 | use Puli\Manager\Asset\DiscoveryAssetManager; |
||
| 39 | use Puli\Manager\Cache\CacheFileStorage; |
||
| 40 | use Puli\Manager\Cache\CacheJsonSerializer; |
||
| 41 | use Puli\Manager\Cache\CacheManagerImpl; |
||
| 42 | use Puli\Manager\Config\ConfigFileManagerImpl; |
||
| 43 | use Puli\Manager\Config\ConfigFileStorage; |
||
| 44 | use Puli\Manager\Config\ConfigJsonSerializer; |
||
| 45 | use Puli\Manager\Config\DefaultConfig; |
||
| 46 | use Puli\Manager\Config\EnvConfig; |
||
| 47 | use Puli\Manager\Discovery\DiscoveryManagerImpl; |
||
| 48 | use Puli\Manager\Factory\FactoryManagerImpl; |
||
| 49 | use Puli\Manager\Factory\Generator\DefaultGeneratorRegistry; |
||
| 50 | use Puli\Manager\Filesystem\FilesystemStorage; |
||
| 51 | use Puli\Manager\Installation\InstallationManagerImpl; |
||
| 52 | use Puli\Manager\Installer\PackageFileInstallerManager; |
||
| 53 | use Puli\Manager\Migration\MigrationManager; |
||
| 54 | use Puli\Manager\Package\PackageFileStorage; |
||
| 55 | use Puli\Manager\Package\PackageJsonSerializer; |
||
| 56 | use Puli\Manager\Package\PackageManagerImpl; |
||
| 57 | use Puli\Manager\Package\RootPackageFileManagerImpl; |
||
| 58 | use Puli\Manager\Php\ClassWriter; |
||
| 59 | use Puli\Manager\Repository\RepositoryManagerImpl; |
||
| 60 | use Puli\Manager\Server\PackageFileServerManager; |
||
| 61 | use Puli\Manager\Util\System; |
||
| 62 | use Puli\Repository\Api\EditableRepository; |
||
| 63 | use Puli\Repository\Api\ResourceRepository; |
||
| 64 | use Puli\UrlGenerator\Api\UrlGenerator; |
||
| 65 | use Puli\UrlGenerator\DiscoveryUrlGenerator; |
||
| 66 | use Symfony\Component\EventDispatcher\EventDispatcherInterface; |
||
| 67 | use Webmozart\Expression\Expr; |
||
| 68 | use Webmozart\PathUtil\Path; |
||
| 69 | |||
| 70 | /** |
||
| 71 | * The Puli service locator. |
||
| 72 | * |
||
| 73 | * Use this class to access the managers provided by this package: |
||
| 74 | * |
||
| 75 | * ```php |
||
| 76 | * $puli = new Puli(getcwd()); |
||
| 77 | * $puli->start(); |
||
| 78 | * |
||
| 79 | * $packageManager = $puli->getPackageManager(); |
||
| 80 | * ``` |
||
| 81 | * |
||
| 82 | * The `Puli` class either operates in the global or a project context: |
||
| 83 | * |
||
| 84 | * * The "global context" is not tied to a specific root package. A global |
||
| 85 | * context only loads the settings of the "config.json" file in the home |
||
| 86 | * directory. The `Puli` class operates in the global context if no |
||
| 87 | * project root directory is passed to the constructor. In the global |
||
| 88 | * context, only the global config file manager is available. |
||
| 89 | * * The "project context" is tied to a specific Puli project. You need to |
||
| 90 | * pass the path to the project's root directory to the constructor or to |
||
| 91 | * {@link setRootDirectory()}. The configuration of the "puli.json" file in |
||
| 92 | * the root directory is used to configure the managers. |
||
| 93 | * |
||
| 94 | * The `Puli` class creates four kinds of managers: |
||
| 95 | * |
||
| 96 | * * The "config file manager" allows you to modify entries of the |
||
| 97 | * "config.json" file in the home directory. |
||
| 98 | * * The "package file manager" manages modifications to the "puli.json" file |
||
| 99 | * of a Puli project. |
||
| 100 | * * The "package manager" manages the package repository of a Puli project. |
||
| 101 | * * The "repository manager" manages the resource repository of a Puli |
||
| 102 | * project. |
||
| 103 | * * The "discovery manager" manages the resource discovery of a Puli project. |
||
| 104 | * |
||
| 105 | * The home directory is read from the context variable "PULI_HOME". |
||
| 106 | * If this variable is not set, the home directory defaults to: |
||
| 107 | * |
||
| 108 | * * `$HOME/.puli` on Linux, where `$HOME` is the context variable |
||
| 109 | * "HOME". |
||
| 110 | * * `$APPDATA/Puli` on Windows, where `$APPDATA` is the context |
||
| 111 | * variable "APPDATA". |
||
| 112 | * |
||
| 113 | * If none of these variables can be found, an exception is thrown. |
||
| 114 | * |
||
| 115 | * A .htaccess file is put into the home directory to protect it from web |
||
| 116 | * access. |
||
| 117 | * |
||
| 118 | * @since 1.0 |
||
| 119 | * |
||
| 120 | * @author Bernhard Schussek <[email protected]> |
||
| 121 | */ |
||
| 122 | class Puli |
||
| 123 | { |
||
| 124 | /** |
||
| 125 | * @var string|null |
||
| 126 | */ |
||
| 127 | private $rootDir; |
||
| 128 | |||
| 129 | /** |
||
| 130 | * @var string |
||
| 131 | */ |
||
| 132 | private $env; |
||
| 133 | |||
| 134 | /** |
||
| 135 | * @var EventDispatcherInterface|null |
||
| 136 | */ |
||
| 137 | private $dispatcher; |
||
| 138 | |||
| 139 | /** |
||
| 140 | * @var Context|ProjectContext |
||
| 141 | */ |
||
| 142 | private $context; |
||
| 143 | |||
| 144 | /** |
||
| 145 | * @var ResourceRepository |
||
| 146 | */ |
||
| 147 | private $repo; |
||
| 148 | |||
| 149 | /** |
||
| 150 | * @var Discovery |
||
| 151 | */ |
||
| 152 | private $discovery; |
||
| 153 | |||
| 154 | /** |
||
| 155 | * @var object |
||
| 156 | */ |
||
| 157 | private $factory; |
||
| 158 | |||
| 159 | /** |
||
| 160 | * @var FactoryManager |
||
| 161 | */ |
||
| 162 | private $factoryManager; |
||
| 163 | |||
| 164 | /** |
||
| 165 | * @var ConfigFileManager |
||
| 166 | */ |
||
| 167 | private $configFileManager; |
||
| 168 | |||
| 169 | /** |
||
| 170 | * @var RootPackageFileManager |
||
| 171 | */ |
||
| 172 | private $rootPackageFileManager; |
||
| 173 | |||
| 174 | /** |
||
| 175 | * @var PackageManager |
||
| 176 | */ |
||
| 177 | private $packageManager; |
||
| 178 | |||
| 179 | /** |
||
| 180 | * @var RepositoryManager |
||
| 181 | */ |
||
| 182 | private $repositoryManager; |
||
| 183 | |||
| 184 | /** |
||
| 185 | * @var DiscoveryManager |
||
| 186 | */ |
||
| 187 | private $discoveryManager; |
||
| 188 | |||
| 189 | /** |
||
| 190 | * @var AssetManager |
||
| 191 | */ |
||
| 192 | private $assetManager; |
||
| 193 | |||
| 194 | /** |
||
| 195 | * @var InstallationManager |
||
| 196 | */ |
||
| 197 | private $installationManager; |
||
| 198 | |||
| 199 | /** |
||
| 200 | * @var InstallerManager |
||
| 201 | */ |
||
| 202 | private $installerManager; |
||
| 203 | |||
| 204 | /** |
||
| 205 | * @var ServerManager |
||
| 206 | */ |
||
| 207 | private $serverManager; |
||
| 208 | |||
| 209 | /** |
||
| 210 | * @var UrlGenerator |
||
| 211 | */ |
||
| 212 | private $urlGenerator; |
||
| 213 | |||
| 214 | /** |
||
| 215 | * @var Storage|null |
||
| 216 | */ |
||
| 217 | private $storage; |
||
| 218 | |||
| 219 | /** |
||
| 220 | * @var ConfigFileStorage|null |
||
| 221 | */ |
||
| 222 | private $configFileStorage; |
||
| 223 | |||
| 224 | /** |
||
| 225 | * @var ConfigFileSerializer|null |
||
| 226 | */ |
||
| 227 | private $configFileSerializer; |
||
| 228 | |||
| 229 | /** |
||
| 230 | * @var PackageFileStorage|null |
||
| 231 | */ |
||
| 232 | private $packageFileStorage; |
||
| 233 | |||
| 234 | /** |
||
| 235 | * @var PackageFileSerializer|null |
||
| 236 | */ |
||
| 237 | private $packageFileSerializer; |
||
| 238 | |||
| 239 | /** |
||
| 240 | * @var LoggerInterface |
||
| 241 | */ |
||
| 242 | private $logger; |
||
| 243 | |||
| 244 | /** |
||
| 245 | * @var bool |
||
| 246 | */ |
||
| 247 | private $started = false; |
||
| 248 | |||
| 249 | /** |
||
| 250 | * @var bool |
||
| 251 | */ |
||
| 252 | private $pluginsEnabled = true; |
||
| 253 | |||
| 254 | /** |
||
| 255 | * @var CacheFileSerializer|null |
||
| 256 | */ |
||
| 257 | private $cacheFileSerializer; |
||
| 258 | |||
| 259 | /** |
||
| 260 | * @var CacheFileStorage|null |
||
| 261 | */ |
||
| 262 | private $cacheFileStorage; |
||
| 263 | |||
| 264 | /** |
||
| 265 | * @var CacheManager|null |
||
| 266 | */ |
||
| 267 | private $cacheManager; |
||
| 268 | |||
| 269 | /** |
||
| 270 | * Parses the system context for a home directory. |
||
| 271 | * |
||
| 272 | * @return null|string Returns the path to the home directory or `null` |
||
| 273 | * if none was found. |
||
| 274 | */ |
||
| 275 | 50 | private static function parseHomeDirectory() |
|
| 276 | { |
||
| 277 | try { |
||
| 278 | 50 | $homeDir = System::parseHomeDirectory(); |
|
| 279 | |||
| 280 | 47 | System::denyWebAccess($homeDir); |
|
| 281 | |||
| 282 | 47 | return $homeDir; |
|
| 283 | 3 | } catch (InvalidConfigException $e) { |
|
| 284 | // Context variable was not found -> no home directory |
||
| 285 | // This happens often on web servers where the home directory is |
||
| 286 | // not set manually |
||
| 287 | 2 | return null; |
|
| 288 | } |
||
| 289 | } |
||
| 290 | |||
| 291 | /** |
||
| 292 | * Creates a new instance for the given Puli project. |
||
| 293 | * |
||
| 294 | * @param string|null $rootDir The root directory of the Puli project. |
||
| 295 | * If none is passed, the object operates in |
||
| 296 | * the global context. You can set or switch |
||
| 297 | * the root directories later on by calling |
||
| 298 | * {@link setRootDirectory()}. |
||
| 299 | * @param string $env One of the {@link Environment} constants. |
||
| 300 | * |
||
| 301 | * @see Puli, start() |
||
| 302 | */ |
||
| 303 | 52 | public function __construct($rootDir = null, $env = Environment::DEV) |
|
| 304 | { |
||
| 305 | 52 | $this->setRootDirectory($rootDir); |
|
| 306 | 52 | $this->setEnvironment($env); |
|
| 307 | 52 | } |
|
| 308 | |||
| 309 | /** |
||
| 310 | * Starts the service container. |
||
| 311 | */ |
||
| 312 | 50 | public function start() |
|
| 313 | { |
||
| 314 | 50 | if ($this->started) { |
|
| 315 | throw new LogicException('Puli is already started'); |
||
| 316 | } |
||
| 317 | |||
| 318 | 50 | if (null !== $this->rootDir) { |
|
| 319 | 27 | $this->context = $this->createProjectContext($this->rootDir, $this->env); |
|
| 320 | 27 | $bootstrapFile = $this->context->getConfig()->get(Config::BOOTSTRAP_FILE); |
|
| 321 | |||
| 322 | // Run the project's bootstrap file to enable project-specific |
||
| 323 | // autoloading |
||
| 324 | 27 | if (null !== $bootstrapFile) { |
|
| 325 | // Backup autoload functions of the PHAR |
||
| 326 | 1 | $autoloadFunctions = spl_autoload_functions(); |
|
| 327 | |||
| 328 | 1 | foreach ($autoloadFunctions as $autoloadFunction) { |
|
| 329 | 1 | spl_autoload_unregister($autoloadFunction); |
|
| 330 | } |
||
| 331 | |||
| 332 | // Add project-specific autoload functions |
||
| 333 | 1 | require_once Path::makeAbsolute($bootstrapFile, $this->rootDir); |
|
| 334 | |||
| 335 | // Prepend autoload functions of the PHAR again |
||
| 336 | // This is needed if the user specific autoload functions were |
||
| 337 | // added with $prepend=true (as done by Composer) |
||
| 338 | // Classes in the PHAR should always take precedence |
||
| 339 | 27 | for ($i = count($autoloadFunctions) - 1; $i >= 0; --$i) { |
|
| 340 | 1 | spl_autoload_register($autoloadFunctions[$i], true, true); |
|
| 341 | } |
||
| 342 | } |
||
| 343 | } else { |
||
| 344 | 23 | $this->context = $this->createGlobalContext(); |
|
| 345 | } |
||
| 346 | |||
| 347 | 49 | $this->dispatcher = $this->context->getEventDispatcher(); |
|
| 348 | 49 | $this->started = true; |
|
| 349 | |||
| 350 | // Start plugins once the container is running |
||
| 351 | 49 | if ($this->rootDir && $this->pluginsEnabled) { |
|
| 352 | 26 | $this->activatePlugins(); |
|
| 353 | } |
||
| 354 | 47 | } |
|
| 355 | |||
| 356 | /** |
||
| 357 | * Returns whether the service container is started. |
||
| 358 | * |
||
| 359 | * @return bool Returns `true` if the container is started and `false` |
||
| 360 | * otherwise. |
||
| 361 | */ |
||
| 362 | public function isStarted() |
||
| 363 | { |
||
| 364 | return $this->started; |
||
| 365 | } |
||
| 366 | |||
| 367 | /** |
||
| 368 | * Sets the root directory of the managed Puli project. |
||
| 369 | * |
||
| 370 | * @param string|null $rootDir The root directory of the managed Puli |
||
| 371 | * project or `null` to start Puli outside of a |
||
| 372 | * specific project. |
||
| 373 | */ |
||
| 374 | 52 | public function setRootDirectory($rootDir) |
|
| 375 | { |
||
| 376 | 52 | if ($this->started) { |
|
| 377 | throw new LogicException('Puli is already started'); |
||
| 378 | } |
||
| 379 | |||
| 380 | 52 | Assert::nullOrDirectory($rootDir); |
|
| 381 | |||
| 382 | 52 | $this->rootDir = $rootDir ? Path::canonicalize($rootDir) : null; |
|
| 383 | 52 | } |
|
| 384 | |||
| 385 | /** |
||
| 386 | * Sets the environment of the managed Puli project. |
||
| 387 | * |
||
| 388 | * @param string $env One of the {@link Environment} constants. |
||
| 389 | */ |
||
| 390 | 52 | public function setEnvironment($env) |
|
| 391 | { |
||
| 392 | 52 | if ($this->started) { |
|
| 393 | throw new LogicException('Puli is already started'); |
||
| 394 | } |
||
| 395 | |||
| 396 | 52 | Assert::oneOf($env, Environment::all(), 'The environment must be one of: %2$s. Got: %s'); |
|
| 397 | |||
| 398 | 52 | $this->env = $env; |
|
| 399 | 52 | } |
|
| 400 | |||
| 401 | /** |
||
| 402 | * Retturns the environment of the managed Puli project. |
||
| 403 | * |
||
| 404 | * @return string One of the {@link Environment} constants. |
||
| 405 | */ |
||
| 406 | 2 | public function getEnvironment() |
|
| 407 | { |
||
| 408 | 2 | return $this->env; |
|
| 409 | } |
||
| 410 | |||
| 411 | /** |
||
| 412 | * Returns the root directory of the managed Puli project. |
||
| 413 | * |
||
| 414 | * If no Puli project is managed at the moment, `null` is returned. |
||
| 415 | * |
||
| 416 | * @return string|null The root directory of the managed Puli project or |
||
| 417 | * `null` if none is set. |
||
| 418 | */ |
||
| 419 | 4 | public function getRootDirectory() |
|
| 420 | { |
||
| 421 | 4 | return $this->rootDir; |
|
| 422 | } |
||
| 423 | |||
| 424 | /** |
||
| 425 | * Sets the logger to use. |
||
| 426 | * |
||
| 427 | * @param LoggerInterface $logger The logger to use. |
||
| 428 | */ |
||
| 429 | public function setLogger(LoggerInterface $logger) |
||
| 430 | { |
||
| 431 | if ($this->started) { |
||
| 432 | throw new LogicException('Puli is already started'); |
||
| 433 | } |
||
| 434 | |||
| 435 | $this->logger = $logger; |
||
| 436 | } |
||
| 437 | |||
| 438 | /** |
||
| 439 | * Returns the used logger. |
||
| 440 | * |
||
| 441 | * @return LoggerInterface The used logger. |
||
| 442 | */ |
||
| 443 | public function getLogger() |
||
| 444 | { |
||
| 445 | return $this->logger; |
||
| 446 | } |
||
| 447 | |||
| 448 | /** |
||
| 449 | * Sets the event dispatcher to use. |
||
| 450 | * |
||
| 451 | * @param EventDispatcherInterface $dispatcher The event dispatcher to use. |
||
| 452 | */ |
||
| 453 | 2 | public function setEventDispatcher(EventDispatcherInterface $dispatcher) |
|
| 454 | { |
||
| 455 | 2 | if ($this->started) { |
|
| 456 | throw new LogicException('Puli is already started'); |
||
| 457 | } |
||
| 458 | |||
| 459 | 2 | $this->dispatcher = $dispatcher; |
|
| 460 | 2 | } |
|
| 461 | |||
| 462 | /** |
||
| 463 | * Returns the used event dispatcher. |
||
| 464 | * |
||
| 465 | * @return EventDispatcherInterface|null The used logger. |
||
| 466 | */ |
||
| 467 | 3 | public function getEventDispatcher() |
|
| 468 | { |
||
| 469 | 3 | return $this->dispatcher; |
|
| 470 | } |
||
| 471 | |||
| 472 | /** |
||
| 473 | * Enables all Puli plugins. |
||
| 474 | */ |
||
| 475 | public function enablePlugins() |
||
| 476 | { |
||
| 477 | $this->pluginsEnabled = true; |
||
| 478 | } |
||
| 479 | |||
| 480 | /** |
||
| 481 | * Disables all Puli plugins. |
||
| 482 | */ |
||
| 483 | 1 | public function disablePlugins() |
|
| 484 | { |
||
| 485 | 1 | $this->pluginsEnabled = false; |
|
| 486 | 1 | } |
|
| 487 | |||
| 488 | /** |
||
| 489 | * Returns whether Puli plugins are enabled. |
||
| 490 | * |
||
| 491 | * @return bool Returns `true` if Puli plugins will be loaded and `false` |
||
| 492 | * otherwise. |
||
| 493 | */ |
||
| 494 | public function arePluginsEnabled() |
||
| 495 | { |
||
| 496 | return $this->pluginsEnabled; |
||
| 497 | } |
||
| 498 | |||
| 499 | /** |
||
| 500 | * Returns the context. |
||
| 501 | * |
||
| 502 | * @return Context|ProjectContext The context. |
||
| 503 | */ |
||
| 504 | 30 | public function getContext() |
|
| 505 | { |
||
| 506 | 30 | if (!$this->started) { |
|
| 507 | throw new LogicException('Puli was not started'); |
||
| 508 | } |
||
| 509 | |||
| 510 | 30 | return $this->context; |
|
| 511 | } |
||
| 512 | |||
| 513 | /** |
||
| 514 | * Returns the resource repository of the project. |
||
| 515 | * |
||
| 516 | * @return EditableRepository The resource repository. |
||
| 517 | */ |
||
| 518 | 8 | View Code Duplication | public function getRepository() |
| 519 | { |
||
| 520 | 8 | if (!$this->started) { |
|
| 521 | throw new LogicException('Puli was not started'); |
||
| 522 | } |
||
| 523 | |||
| 524 | 8 | if (!$this->context instanceof ProjectContext) { |
|
| 525 | 1 | return null; |
|
| 526 | } |
||
| 527 | |||
| 528 | 7 | if (!$this->repo) { |
|
| 529 | 7 | $this->repo = $this->getFactory()->createRepository(); |
|
| 530 | } |
||
| 531 | |||
| 532 | 7 | return $this->repo; |
|
| 533 | } |
||
| 534 | |||
| 535 | /** |
||
| 536 | * Returns the resource discovery of the project. |
||
| 537 | * |
||
| 538 | * @return EditableDiscovery The resource discovery. |
||
| 539 | */ |
||
| 540 | 5 | View Code Duplication | public function getDiscovery() |
| 541 | { |
||
| 542 | 5 | if (!$this->started) { |
|
| 543 | throw new LogicException('Puli was not started'); |
||
| 544 | } |
||
| 545 | |||
| 546 | 5 | if (!$this->context instanceof ProjectContext) { |
|
| 547 | 1 | return null; |
|
| 548 | } |
||
| 549 | |||
| 550 | 4 | if (!$this->discovery) { |
|
| 551 | 4 | $this->discovery = $this->getFactory()->createDiscovery($this->getRepository()); |
|
| 552 | } |
||
| 553 | |||
| 554 | 4 | return $this->discovery; |
|
| 555 | } |
||
| 556 | |||
| 557 | /** |
||
| 558 | * @return object |
||
| 559 | */ |
||
| 560 | 9 | public function getFactory() |
|
| 561 | { |
||
| 562 | 9 | if (!$this->started) { |
|
| 563 | throw new LogicException('Puli was not started'); |
||
| 564 | } |
||
| 565 | |||
| 566 | 9 | if (!$this->factory && $this->context instanceof ProjectContext) { |
|
| 567 | 8 | $this->factory = $this->getFactoryManager()->createFactory(); |
|
| 568 | } |
||
| 569 | |||
| 570 | 9 | return $this->factory; |
|
| 571 | } |
||
| 572 | |||
| 573 | /** |
||
| 574 | * @return FactoryManager |
||
| 575 | */ |
||
| 576 | 16 | public function getFactoryManager() |
|
| 577 | { |
||
| 578 | 16 | if (!$this->started) { |
|
| 579 | throw new LogicException('Puli was not started'); |
||
| 580 | } |
||
| 581 | |||
| 582 | 16 | if (!$this->factoryManager && $this->context instanceof ProjectContext) { |
|
| 583 | 14 | $this->factoryManager = new FactoryManagerImpl( |
|
| 584 | 14 | $this->context, |
|
| 585 | 14 | new DefaultGeneratorRegistry(), |
|
| 586 | 14 | new ClassWriter() |
|
| 587 | ); |
||
| 588 | |||
| 589 | // Don't set via the constructor to prevent cyclic dependencies |
||
| 590 | 14 | $this->factoryManager->setPackages($this->getPackageManager()->getPackages()); |
|
| 591 | 14 | $this->factoryManager->setServers($this->getServerManager()->getServers()); |
|
| 592 | } |
||
| 593 | |||
| 594 | 16 | return $this->factoryManager; |
|
| 595 | } |
||
| 596 | |||
| 597 | /** |
||
| 598 | * Returns the configuration file manager. |
||
| 599 | * |
||
| 600 | * @return ConfigFileManager The configuration file manager. |
||
| 601 | */ |
||
| 602 | 2 | public function getConfigFileManager() |
|
| 603 | { |
||
| 604 | 2 | if (!$this->started) { |
|
| 605 | throw new LogicException('Puli was not started'); |
||
| 606 | } |
||
| 607 | |||
| 608 | 2 | if (!$this->configFileManager && $this->context->getHomeDirectory()) { |
|
| 609 | 2 | $this->configFileManager = new ConfigFileManagerImpl( |
|
| 610 | 2 | $this->context, |
|
| 611 | 2 | $this->getConfigFileStorage(), |
|
| 612 | 2 | $this->getFactoryManager() |
|
| 613 | ); |
||
| 614 | } |
||
| 615 | |||
| 616 | 2 | return $this->configFileManager; |
|
| 617 | } |
||
| 618 | |||
| 619 | /** |
||
| 620 | * Returns the root package file manager. |
||
| 621 | * |
||
| 622 | * @return RootPackageFileManager The package file manager. |
||
| 623 | */ |
||
| 624 | 15 | View Code Duplication | public function getRootPackageFileManager() |
| 625 | { |
||
| 626 | 15 | if (!$this->started) { |
|
| 627 | throw new LogicException('Puli was not started'); |
||
| 628 | } |
||
| 629 | |||
| 630 | 15 | if (!$this->rootPackageFileManager && $this->context instanceof ProjectContext) { |
|
| 631 | 14 | $this->rootPackageFileManager = new RootPackageFileManagerImpl( |
|
| 632 | 14 | $this->context, |
|
| 633 | 14 | $this->getPackageFileStorage() |
|
| 634 | ); |
||
| 635 | } |
||
| 636 | |||
| 637 | 15 | return $this->rootPackageFileManager; |
|
| 638 | } |
||
| 639 | |||
| 640 | /** |
||
| 641 | * Returns the package manager. |
||
| 642 | * |
||
| 643 | * @return PackageManager The package manager. |
||
| 644 | */ |
||
| 645 | 15 | View Code Duplication | public function getPackageManager() |
| 646 | { |
||
| 647 | 15 | if (!$this->started) { |
|
| 648 | throw new LogicException('Puli was not started'); |
||
| 649 | } |
||
| 650 | |||
| 651 | 15 | if (!$this->packageManager && $this->context instanceof ProjectContext) { |
|
| 652 | 14 | $this->packageManager = new PackageManagerImpl( |
|
| 653 | 14 | $this->context, |
|
| 654 | 14 | $this->getPackageFileStorage() |
|
| 655 | ); |
||
| 656 | } |
||
| 657 | |||
| 658 | 15 | return $this->packageManager; |
|
| 659 | } |
||
| 660 | |||
| 661 | /** |
||
| 662 | * Returns the resource repository manager. |
||
| 663 | * |
||
| 664 | * @return RepositoryManager The repository manager. |
||
| 665 | */ |
||
| 666 | 2 | View Code Duplication | public function getRepositoryManager() |
| 667 | { |
||
| 668 | 2 | if (!$this->started) { |
|
| 669 | throw new LogicException('Puli was not started'); |
||
| 670 | } |
||
| 671 | |||
| 672 | 2 | if (!$this->repositoryManager && $this->context instanceof ProjectContext) { |
|
| 673 | 1 | $this->repositoryManager = new RepositoryManagerImpl( |
|
| 674 | 1 | $this->context, |
|
| 675 | 1 | $this->getRepository(), |
|
| 676 | 1 | $this->getPackageManager()->findPackages(Expr::method('isEnabled', Expr::same(true))), |
|
| 677 | 1 | $this->getPackageFileStorage() |
|
| 678 | ); |
||
| 679 | } |
||
| 680 | |||
| 681 | 2 | return $this->repositoryManager; |
|
| 682 | } |
||
| 683 | |||
| 684 | /** |
||
| 685 | * Returns the resource discovery manager. |
||
| 686 | * |
||
| 687 | * @return DiscoveryManager The discovery manager. |
||
| 688 | */ |
||
| 689 | 3 | View Code Duplication | public function getDiscoveryManager() |
| 690 | { |
||
| 691 | 3 | if (!$this->started) { |
|
| 692 | throw new LogicException('Puli was not started'); |
||
| 693 | } |
||
| 694 | |||
| 695 | 3 | if (!$this->discoveryManager && $this->context instanceof ProjectContext) { |
|
| 696 | 2 | $this->discoveryManager = new DiscoveryManagerImpl( |
|
| 697 | 2 | $this->context, |
|
| 698 | 2 | $this->getDiscovery(), |
|
| 699 | 2 | $this->getPackageManager()->findPackages(Expr::method('isEnabled', Expr::same(true))), |
|
| 700 | 2 | $this->getPackageFileStorage(), |
|
| 701 | 2 | $this->logger |
|
| 702 | ); |
||
| 703 | } |
||
| 704 | |||
| 705 | 3 | return $this->discoveryManager; |
|
| 706 | } |
||
| 707 | |||
| 708 | /** |
||
| 709 | * Returns the asset manager. |
||
| 710 | * |
||
| 711 | * @return AssetManager The asset manager. |
||
| 712 | */ |
||
| 713 | 2 | public function getAssetManager() |
|
| 714 | { |
||
| 715 | 2 | if (!$this->started) { |
|
| 716 | throw new LogicException('Puli was not started'); |
||
| 717 | } |
||
| 718 | |||
| 719 | 2 | if (!$this->assetManager && $this->context instanceof ProjectContext) { |
|
| 720 | 1 | $this->assetManager = new DiscoveryAssetManager( |
|
| 721 | 1 | $this->getDiscoveryManager(), |
|
| 722 | 1 | $this->getServerManager()->getServers() |
|
| 723 | ); |
||
| 724 | } |
||
| 725 | |||
| 726 | 2 | return $this->assetManager; |
|
| 727 | } |
||
| 728 | |||
| 729 | /** |
||
| 730 | * Returns the installation manager. |
||
| 731 | * |
||
| 732 | * @return InstallationManager The installation manager. |
||
| 733 | */ |
||
| 734 | 2 | public function getInstallationManager() |
|
| 735 | { |
||
| 736 | 2 | if (!$this->started) { |
|
| 737 | throw new LogicException('Puli was not started'); |
||
| 738 | } |
||
| 739 | |||
| 740 | 2 | if (!$this->installationManager && $this->context instanceof ProjectContext) { |
|
| 741 | 1 | $this->installationManager = new InstallationManagerImpl( |
|
| 742 | 1 | $this->getContext(), |
|
| 743 | 1 | $this->getRepository(), |
|
| 744 | 1 | $this->getServerManager()->getServers(), |
|
| 745 | 1 | $this->getInstallerManager() |
|
| 746 | ); |
||
| 747 | } |
||
| 748 | |||
| 749 | 2 | return $this->installationManager; |
|
| 750 | } |
||
| 751 | |||
| 752 | /** |
||
| 753 | * Returns the installer manager. |
||
| 754 | * |
||
| 755 | * @return InstallerManager The installer manager. |
||
| 756 | */ |
||
| 757 | 15 | public function getInstallerManager() |
|
| 758 | { |
||
| 759 | 15 | if (!$this->started) { |
|
| 760 | throw new LogicException('Puli was not started'); |
||
| 761 | } |
||
| 762 | |||
| 763 | 15 | if (!$this->installerManager && $this->context instanceof ProjectContext) { |
|
| 764 | 14 | $this->installerManager = new PackageFileInstallerManager( |
|
| 765 | 14 | $this->getRootPackageFileManager(), |
|
| 766 | 14 | $this->getPackageManager()->getPackages() |
|
| 767 | ); |
||
| 768 | } |
||
| 769 | |||
| 770 | 15 | return $this->installerManager; |
|
| 771 | } |
||
| 772 | |||
| 773 | /** |
||
| 774 | * Returns the server manager. |
||
| 775 | * |
||
| 776 | * @return ServerManager The server manager. |
||
| 777 | */ |
||
| 778 | 15 | public function getServerManager() |
|
| 779 | { |
||
| 780 | 15 | if (!$this->started) { |
|
| 781 | throw new LogicException('Puli was not started'); |
||
| 782 | } |
||
| 783 | |||
| 784 | 15 | if (!$this->serverManager && $this->context instanceof ProjectContext) { |
|
| 785 | 14 | $this->serverManager = new PackageFileServerManager( |
|
| 786 | 14 | $this->getRootPackageFileManager(), |
|
| 787 | 14 | $this->getInstallerManager() |
|
| 788 | ); |
||
| 789 | } |
||
| 790 | |||
| 791 | 15 | return $this->serverManager; |
|
| 792 | } |
||
| 793 | |||
| 794 | /** |
||
| 795 | * Returns the resource URL generator. |
||
| 796 | * |
||
| 797 | * @return UrlGenerator The resource URL generator. |
||
| 798 | */ |
||
| 799 | 2 | public function getUrlGenerator() |
|
| 800 | { |
||
| 801 | 2 | if (!$this->started) { |
|
| 802 | throw new LogicException('Puli was not started'); |
||
| 803 | } |
||
| 804 | |||
| 805 | 2 | if (!$this->urlGenerator && $this->context instanceof ProjectContext) { |
|
| 806 | 1 | $urlFormats = array(); |
|
| 807 | 1 | foreach ($this->getServerManager()->getServers() as $server) { |
|
| 808 | $urlFormats[$server->getName()] = $server->getUrlFormat(); |
||
| 809 | } |
||
| 810 | |||
| 811 | 1 | $this->urlGenerator = new DiscoveryUrlGenerator($this->getDiscovery(), $urlFormats); |
|
| 812 | } |
||
| 813 | |||
| 814 | 2 | return $this->urlGenerator; |
|
| 815 | } |
||
| 816 | |||
| 817 | /** |
||
| 818 | * Returns the cached file storage. |
||
| 819 | * |
||
| 820 | * @return Storage The storage. |
||
| 821 | */ |
||
| 822 | 48 | public function getStorage() |
|
| 823 | { |
||
| 824 | 48 | if (!$this->storage) { |
|
| 825 | 48 | $this->storage = new FilesystemStorage(); |
|
| 826 | } |
||
| 827 | |||
| 828 | 48 | return $this->storage; |
|
| 829 | } |
||
| 830 | |||
| 831 | /** |
||
| 832 | * Returns the cached configuration file serializer. |
||
| 833 | * |
||
| 834 | * @return ConfigFileSerializer The configuration file serializer. |
||
| 835 | */ |
||
| 836 | 47 | public function getConfigFileSerializer() |
|
| 837 | { |
||
| 838 | 47 | if (!$this->configFileSerializer) { |
|
| 839 | 47 | $this->configFileSerializer = new ConfigJsonSerializer(); |
|
| 840 | } |
||
| 841 | |||
| 842 | 47 | return $this->configFileSerializer; |
|
| 843 | } |
||
| 844 | |||
| 845 | /** |
||
| 846 | * Returns the cached package file serializer. |
||
| 847 | * |
||
| 848 | * @return PackageFileSerializer The package file serializer. |
||
| 849 | */ |
||
| 850 | 27 | public function getPackageFileSerializer() |
|
| 851 | { |
||
| 852 | 27 | if (!$this->packageFileSerializer) { |
|
| 853 | 27 | $this->packageFileSerializer = new PackageJsonSerializer( |
|
| 854 | 27 | new MigrationManager(array( |
|
| 855 | // Add future migrations here |
||
| 856 | 27 | )), |
|
| 857 | 27 | __DIR__.'/../../res/schema' |
|
| 858 | ); |
||
| 859 | } |
||
| 860 | |||
| 861 | 27 | return $this->packageFileSerializer; |
|
| 862 | } |
||
| 863 | |||
| 864 | /** |
||
| 865 | * Returns the cache file serializer. |
||
| 866 | * |
||
| 867 | * @return CacheFileSerializer The cache file serializer. |
||
| 868 | */ |
||
| 869 | public function getCacheFileSerializer() |
||
| 870 | { |
||
| 871 | if (!$this->cacheFileSerializer) { |
||
| 872 | $this->cacheFileSerializer = new CacheJsonSerializer($this->getPackageFileSerializer()); |
||
|
0 ignored issues
–
show
|
|||
| 873 | } |
||
| 874 | |||
| 875 | return $this->cacheFileSerializer; |
||
| 876 | } |
||
| 877 | |||
| 878 | /** |
||
| 879 | * Returns the cache file storage. |
||
| 880 | * |
||
| 881 | * @return CacheFileStorage The cache file storage. |
||
| 882 | */ |
||
| 883 | public function getCacheFileStorage() |
||
| 884 | { |
||
| 885 | if (!$this->cacheFileStorage) { |
||
| 886 | $this->cacheFileStorage = new CacheFileStorage( |
||
| 887 | $this->getStorage(), |
||
| 888 | $this->getCacheFileSerializer() |
||
| 889 | ); |
||
| 890 | } |
||
| 891 | |||
| 892 | return $this->cacheFileStorage; |
||
| 893 | } |
||
| 894 | |||
| 895 | /** |
||
| 896 | * Returns the cached configuration manager. |
||
| 897 | * |
||
| 898 | * @return CacheManager The cached configuration manager. |
||
| 899 | */ |
||
| 900 | public function getCacheManager() |
||
| 901 | { |
||
| 902 | if (!$this->cacheManager) { |
||
| 903 | $this->cacheManager = new CacheManagerImpl( |
||
| 904 | $this->getPackageManager(), |
||
| 905 | $this->getCacheFileStorage(), |
||
| 906 | $this->context |
||
|
0 ignored issues
–
show
$this->context of type object<Puli\Manager\Api\Context\Context> is not a sub-type of object<Puli\Manager\Api\Context\ProjectContext>. It seems like you assume a child class of the class Puli\Manager\Api\Context\Context to be always present.
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass. Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type. Loading history...
|
|||
| 907 | ); |
||
| 908 | } |
||
| 909 | |||
| 910 | return $this->cacheManager; |
||
| 911 | } |
||
| 912 | |||
| 913 | 26 | private function activatePlugins() |
|
| 914 | { |
||
| 915 | 26 | foreach ($this->context->getRootPackageFile()->getPluginClasses() as $pluginClass) { |
|
| 916 | 25 | $this->validatePluginClass($pluginClass); |
|
| 917 | |||
| 918 | /** @var PuliPlugin $plugin */ |
||
| 919 | 23 | $plugin = new $pluginClass(); |
|
| 920 | 23 | $plugin->activate($this); |
|
| 921 | } |
||
| 922 | 24 | } |
|
| 923 | |||
| 924 | 23 | private function createGlobalContext() |
|
| 925 | { |
||
| 926 | 23 | $baseConfig = new DefaultConfig(); |
|
| 927 | 23 | $homeDir = self::parseHomeDirectory(); |
|
| 928 | |||
| 929 | 22 | if (null !== $configFile = $this->loadConfigFile($homeDir, $baseConfig)) { |
|
| 930 | 20 | $baseConfig = $configFile->getConfig(); |
|
| 931 | } |
||
| 932 | |||
| 933 | 22 | $config = new EnvConfig($baseConfig); |
|
| 934 | |||
| 935 | 22 | return new Context($homeDir, $config, $configFile, $this->dispatcher); |
|
| 936 | } |
||
| 937 | |||
| 938 | /** |
||
| 939 | * Creates the context of a Puli project. |
||
| 940 | * |
||
| 941 | * The home directory is read from the context variable "PULI_HOME". |
||
| 942 | * If this variable is not set, the home directory defaults to: |
||
| 943 | * |
||
| 944 | * * `$HOME/.puli` on Linux, where `$HOME` is the context variable |
||
| 945 | * "HOME". |
||
| 946 | * * `$APPDATA/Puli` on Windows, where `$APPDATA` is the context |
||
| 947 | * variable "APPDATA". |
||
| 948 | * |
||
| 949 | * If none of these variables can be found, an exception is thrown. |
||
| 950 | * |
||
| 951 | * A .htaccess file is put into the home directory to protect it from web |
||
| 952 | * access. |
||
| 953 | * |
||
| 954 | * @param string $rootDir The path to the project. |
||
| 955 | * |
||
| 956 | * @return ProjectContext The project context. |
||
| 957 | */ |
||
| 958 | 27 | private function createProjectContext($rootDir, $env) |
|
| 959 | { |
||
| 960 | 27 | Assert::fileExists($rootDir, 'Could not load Puli context: The root %s does not exist.'); |
|
| 961 | 27 | Assert::directory($rootDir, 'Could not load Puli context: The root %s is a file. Expected a directory.'); |
|
| 962 | |||
| 963 | 27 | $baseConfig = new DefaultConfig(); |
|
| 964 | 27 | $homeDir = self::parseHomeDirectory(); |
|
| 965 | |||
| 966 | 27 | if (null !== $configFile = $this->loadConfigFile($homeDir, $baseConfig)) { |
|
| 967 | 26 | $baseConfig = $configFile->getConfig(); |
|
| 968 | } |
||
| 969 | |||
| 970 | // Create a storage without the factory manager |
||
| 971 | 27 | $packageFileStorage = new PackageFileStorage($this->getStorage(), $this->getPackageFileSerializer()); |
|
| 972 | 27 | $rootDir = Path::canonicalize($rootDir); |
|
| 973 | 27 | $rootFilePath = $this->rootDir.'/puli.json'; |
|
| 974 | |||
| 975 | try { |
||
| 976 | 27 | $rootPackageFile = $packageFileStorage->loadRootPackageFile($rootFilePath, $baseConfig); |
|
| 977 | 1 | } catch (FileNotFoundException $e) { |
|
| 978 | 1 | $rootPackageFile = new RootPackageFile(null, $rootFilePath, $baseConfig); |
|
| 979 | } |
||
| 980 | |||
| 981 | 27 | $config = new EnvConfig($rootPackageFile->getConfig()); |
|
| 982 | |||
| 983 | 27 | return new ProjectContext($homeDir, $rootDir, $config, $rootPackageFile, $configFile, $this->dispatcher, $env); |
|
| 984 | } |
||
| 985 | |||
| 986 | /** |
||
| 987 | * Returns the cached configuration file storage. |
||
| 988 | * |
||
| 989 | * @return ConfigFileStorage The configuration file storage. |
||
| 990 | */ |
||
| 991 | 2 | private function getConfigFileStorage() |
|
| 992 | { |
||
| 993 | 2 | if (!$this->configFileStorage) { |
|
| 994 | 2 | $this->configFileStorage = new ConfigFileStorage( |
|
| 995 | 2 | $this->getStorage(), |
|
| 996 | 2 | $this->getConfigFileSerializer(), |
|
| 997 | 2 | $this->getFactoryManager() |
|
| 998 | ); |
||
| 999 | } |
||
| 1000 | |||
| 1001 | 2 | return $this->configFileStorage; |
|
| 1002 | } |
||
| 1003 | |||
| 1004 | /** |
||
| 1005 | * Returns the cached package file storage. |
||
| 1006 | * |
||
| 1007 | * @return PackageFileStorage The package file storage. |
||
| 1008 | */ |
||
| 1009 | 14 | private function getPackageFileStorage() |
|
| 1010 | { |
||
| 1011 | 14 | if (!$this->packageFileStorage) { |
|
| 1012 | 14 | $this->packageFileStorage = new PackageFileStorage( |
|
| 1013 | 14 | $this->getStorage(), |
|
| 1014 | 14 | $this->getPackageFileSerializer(), |
|
| 1015 | 14 | $this->getFactoryManager() |
|
| 1016 | ); |
||
| 1017 | } |
||
| 1018 | |||
| 1019 | 14 | return $this->packageFileStorage; |
|
| 1020 | } |
||
| 1021 | |||
| 1022 | /** |
||
| 1023 | * Validates the given plugin class name. |
||
| 1024 | * |
||
| 1025 | * @param string $pluginClass The fully qualified name of a plugin class. |
||
| 1026 | */ |
||
| 1027 | 25 | private function validatePluginClass($pluginClass) |
|
| 1028 | { |
||
| 1029 | 25 | if (!class_exists($pluginClass)) { |
|
| 1030 | 1 | throw new InvalidConfigException(sprintf( |
|
| 1031 | 1 | 'The plugin class %s does not exist.', |
|
| 1032 | $pluginClass |
||
| 1033 | )); |
||
| 1034 | } |
||
| 1035 | |||
| 1036 | 24 | if (!in_array('Puli\Manager\Api\PuliPlugin', class_implements($pluginClass))) { |
|
| 1037 | 1 | throw new InvalidConfigException(sprintf( |
|
| 1038 | 1 | 'The plugin class %s must implement PuliPlugin.', |
|
| 1039 | $pluginClass |
||
| 1040 | )); |
||
| 1041 | } |
||
| 1042 | 23 | } |
|
| 1043 | |||
| 1044 | 49 | private function loadConfigFile($homeDir, Config $baseConfig) |
|
| 1045 | { |
||
| 1046 | 49 | if (null === $homeDir) { |
|
| 1047 | 2 | return null; |
|
| 1048 | } |
||
| 1049 | |||
| 1050 | 47 | Assert::fileExists($homeDir, 'Could not load Puli context: The home directory %s does not exist.'); |
|
| 1051 | 47 | Assert::directory($homeDir, 'Could not load Puli context: The home directory %s is a file. Expected a directory.'); |
|
| 1052 | |||
| 1053 | // Create a storage without the factory manager |
||
| 1054 | 47 | $configStorage = new ConfigFileStorage($this->getStorage(), $this->getConfigFileSerializer()); |
|
| 1055 | 47 | $configPath = Path::canonicalize($homeDir).'/config.json'; |
|
| 1056 | |||
| 1057 | try { |
||
| 1058 | 47 | return $configStorage->loadConfigFile($configPath, $baseConfig); |
|
| 1059 | 1 | } catch (FileNotFoundException $e) { |
|
| 1060 | // It's ok if no config.json exists. We'll work with |
||
| 1061 | // DefaultConfig instead |
||
| 1062 | 1 | return null; |
|
| 1063 | } |
||
| 1064 | } |
||
| 1065 | } |
||
| 1066 |
This check looks for parameters that are defined as one type in their type hint or doc comment but seem to be used as a narrower type, i.e an implementation of an interface or a subclass.
Consider changing the type of the parameter or doing an instanceof check before assuming your parameter is of the expected type.