* Modules, themes, and extensions * Publisher profiles and verification metadata * Installed-package tracking * Semantic version compatibility checks * PHP, Laravel, and Content Manager compatibility checks * Dependency resolution * SHA-256 checksum validation * Package signature requirements * Installation and update history * Enable and disable controls * Removal handling * Rollback records * Licence records * Marketplace administration UI * Authenticated REST endpoints * Console audit and synchronisation commands * Permissions and sidebar integration * Feature tests
40 lines
3.4 KiB
PHP
40 lines
3.4 KiB
PHP
<?php
|
|
namespace Modules\Marketplace\Services;
|
|
use Illuminate\Support\Facades\DB;
|
|
use RuntimeException;
|
|
use Modules\Marketplace\Models\Installation;
|
|
use Modules\Marketplace\Models\InstalledPackage;
|
|
use Modules\Marketplace\Models\MarketplacePackage;
|
|
final class MarketplaceManager
|
|
{
|
|
public function __construct(private PackageManifest $manifests,private CompatibilityChecker $compatibility,private DependencyResolver $dependencies) {}
|
|
public function install(MarketplacePackage $package,?int $userId=null): InstalledPackage
|
|
{
|
|
if (!config('marketplace.enabled')) throw new RuntimeException('The marketplace is disabled.');
|
|
$manifest=$this->manifests->parse($package->manifest ?: ['name'=>$package->package_name,'type'=>$package->type,'version'=>$package->latest_version]);
|
|
$compatibility=$this->compatibility->check($manifest); if (!$compatibility['compatible']) throw new RuntimeException(implode(' ',$compatibility['errors']));
|
|
$dependencies=$this->dependencies->resolve($manifest); if (!$dependencies['satisfied']) throw new RuntimeException('Package dependencies are not satisfied.');
|
|
return DB::transaction(function() use ($package,$manifest,$userId) {
|
|
$installed=InstalledPackage::query()->firstOrNew(['package_name'=>$package->package_name]); $from=$installed->exists?$installed->version:null;
|
|
$installed->fill(['marketplace_package_id'=>$package->id,'type'=>$package->type,'version'=>$manifest['version'],'status'=>'installed','manifest'=>$manifest,'checksum'=>$package->checksum,'is_enabled'=>true,'installed_by'=>$userId,'installed_at'=>$installed->installed_at ?: now(),'updated_at_marketplace'=>now()])->save();
|
|
$this->history($installed,$from?'update':'install',$from,$manifest['version'],$userId,'completed'); return $installed->refresh();
|
|
});
|
|
}
|
|
public function setEnabled(InstalledPackage $package,bool $enabled,?int $userId=null): InstalledPackage
|
|
{
|
|
$package->update(['is_enabled'=>$enabled,'status'=>$enabled?'installed':'disabled']); $this->history($package,$enabled?'enable':'disable',$package->version,$package->version,$userId,'completed'); return $package->refresh();
|
|
}
|
|
public function remove(InstalledPackage $package,?int $userId=null): void
|
|
{
|
|
DB::transaction(function() use ($package,$userId) { $this->history($package,'remove',$package->version,null,$userId,'completed'); $package->update(['status'=>'removed','is_enabled'=>false]); });
|
|
}
|
|
public function rollback(InstalledPackage $package,Installation $installation,?int $userId=null): InstalledPackage
|
|
{
|
|
if ($installation->package_name!==$package->package_name || blank($installation->from_version)) throw new RuntimeException('This installation cannot be rolled back.');
|
|
$current=$package->version; $package->update(['version'=>$installation->from_version,'status'=>'installed','is_enabled'=>true]);
|
|
$this->history($package,'rollback',$current,$installation->from_version,$userId,'completed'); return $package->refresh();
|
|
}
|
|
private function history(InstalledPackage $package,string $operation,?string $from,?string $to,?int $userId,string $status): Installation
|
|
{ return Installation::query()->create(['installed_package_id'=>$package->id,'package_name'=>$package->package_name,'operation'=>$operation,'from_version'=>$from,'to_version'=>$to,'status'=>$status,'performed_by'=>$userId,'started_at'=>now(),'completed_at'=>now()]); }
|
|
}
|