diff --git a/.gitignore b/.gitignore
index 4f38912..7720681 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,6 @@
.idea
+assets/img
+assets/app*
+assets/mix-manifest.json
vendor
composer.lock
diff --git a/CHANGELOG.md b/CHANGELOG.md
new file mode 100644
index 0000000..4fbce92
--- /dev/null
+++ b/CHANGELOG.md
@@ -0,0 +1,22 @@
+# Changelog
+All notable changes to this project will be documented in this file.
+
+The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
+and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
+
+## [2.0.0] - 2021-11-05
+### Added
+- PHP 7.4 and PHP 8.0 support.
+
+### Changed
+- The location of the Horizon assets has been changed. The Horizon assets are published into the plugin directory itself (`plugins/vdlp/horizon/assets`). Please note that you need to re-publish the assets when you are deploying your October CMS website or application using the `php artisan horizon:assets` command otherwise the Horizon Dashboard will not be available.
+- The `horizon:assets` command can now be used to (re-)publish the Horizon Assets required for the Horizon Dashboard.
+- Renamed `PushExampleJobs` to `PushExampleJobsCommand`.
+
+### Removed
+- Removed the dependency of the October CMS module (for headless applications).
+- Support for PHP 7.1
+
+## [1.0.0] - 2021-06-22
+
+- First release of `vdlp/oc-horizon-plugin`.
diff --git a/Plugin.php b/Plugin.php
index 17491fa..7fade00 100644
--- a/Plugin.php
+++ b/Plugin.php
@@ -11,15 +11,13 @@
use Illuminate\Notifications\NotificationServiceProvider;
use Laravel\Horizon\Horizon;
use System\Classes\PluginBase;
-use Vdlp\Horizon\Console\PushExampleJobs;
+use Vdlp\Horizon\Console\InstallCommand;
+use Vdlp\Horizon\Console\PushExampleJobsCommand;
use Vdlp\Horizon\ServiceProviders\HorizonServiceProvider;
final class Plugin extends PluginBase
{
- /**
- * @var Backend
- */
- private $backend;
+ private Backend $backend;
public function __construct($app)
{
@@ -32,7 +30,7 @@ public function pluginDetails(): array
{
return [
'name' => 'Horizon',
- 'description' => 'Laravel Horizon integration for OctoberCMS',
+ 'description' => 'Laravel Horizon integration for October CMS',
'author' => 'Van der Let & Partners',
'icon' => 'icon-area-chart',
'homepage' => 'https://octobercms.com/plugin/vdlp-horizon',
@@ -43,8 +41,8 @@ public function boot(): void
{
config()->set('app.env', $this->app->environment());
- Horizon::auth(static function () {
- /** @var User $user */
+ Horizon::auth(static function (): bool {
+ /** @var ?User $user */
$user = AuthManager::instance()->getUser();
if ($user === null) {
@@ -60,8 +58,10 @@ public function boot(): void
$this->bootNotificationSettings();
if (config('app.debug') === true) {
- $this->registerConsoleCommand(PushExampleJobs::class, PushExampleJobs::class);
+ $this->registerConsoleCommand(PushExampleJobsCommand::class, PushExampleJobsCommand::class);
}
+
+ $this->registerConsoleCommand(InstallCommand::class, InstallCommand::class);
}
public function register(): void
@@ -79,32 +79,26 @@ public function registerSchedule($schedule): void
public function registerPermissions(): array
{
- return array_merge(
- (array) parent::registerPermissions(),
- [
- 'vdlp.horizon.access_dashboard' => [
- 'tab' => 'Horizon',
- 'label' => 'Access to the Horizon dashboard',
- 'roles' => ['developer'],
- ],
- ]
- );
+ return [
+ 'vdlp.horizon.access_dashboard' => [
+ 'tab' => 'Horizon',
+ 'label' => 'Access to the Horizon dashboard',
+ 'roles' => ['developer'],
+ ],
+ ];
}
public function registerNavigation(): array
{
- return array_merge(
- (array) parent::registerNavigation(),
- [
- 'dashboard' => [
- 'label' => 'Horizon',
- 'url' => $this->backend->url('vdlp/horizon/dashboard'),
- 'iconSvg' => '/plugins/vdlp/horizon/assets/icons/horizon.svg',
- 'permissions' => ['vdlp.horizon.access_dashboard'],
- 'order' => 500,
- ],
- ]
- );
+ return [
+ 'dashboard' => [
+ 'label' => 'Horizon',
+ 'url' => $this->backend->url('vdlp/horizon/dashboard'),
+ 'iconSvg' => '/plugins/vdlp/horizon/assets/icons/horizon.svg',
+ 'permissions' => ['vdlp.horizon.access_dashboard'],
+ 'order' => 500,
+ ],
+ ];
}
public function registerMailTemplates(): array
@@ -116,20 +110,20 @@ public function registerMailTemplates(): array
private function bootNotificationSettings(): void
{
- if (config('vdlp.horizon::mail_notifications_enabled', false)) {
+ if ((bool) config('vdlp.horizon::mail_notifications_enabled', false)) {
Horizon::routeMailNotificationsTo(
config('vdlp.horizon::mail_notifications_to')
);
}
- if (config('vdlp.horizon::slack_notifications_enabled', false)) {
+ if ((bool) config('vdlp.horizon::slack_notifications_enabled', false)) {
Horizon::routeSlackNotificationsTo(
config('vdlp.horizon::slack_notifications_webhook_url'),
config('vdlp.horizon::slack_notifications_channel')
);
}
- if (config('vdlp.horizon::sms_notifications_enabled', false)) {
+ if ((bool) config('vdlp.horizon::sms_notifications_enabled', false)) {
Horizon::routeSmsNotificationsTo(
config('vdlp.horizon::sms_notifications_to')
);
diff --git a/README.md b/README.md
index d4ad487..53ba141 100644
--- a/README.md
+++ b/README.md
@@ -18,8 +18,8 @@ Horizon is 100% open source, so you're free to dig through the source to see exa
## Requirements
-* October CMS 1.0
-* Due to its usage of async process signals, Horizon requires **PHP 7.1+**.
+* October CMS 1.0 or higher
+* PHP 7.4 or PHP 8.0+
* PHP extensions: `ext-pcntl`, `ext-posix` and `ext-redis`.
* Supervisor, see [Laravel 6.x supervisor configuration](https://laravel.com/docs/6.x/queues#supervisor-configuration).
@@ -53,22 +53,22 @@ You should add the `dont-discover` option to your projects `composer.json` file
> IMPORTANT: Make sure the `composer.json` is deployed to your hosting site. This will be parsed by te framework to determine which service providers should be ignored.
-## Assets
-
-* Run the command to publish assets for the Horizon dashboard:
+## Assets & Configuration
```
-php artisan vendor:publish --tag horizon-assets --force
+php artisan horizon:install
```
-## Configuration
+## Update Horizon Assets
-* Run the command to publish configuration file `config/horizon.php`:
+To update the Horizon Assets you can use the following command:
```
-php artisan vendor:publish --tag horizon-config --force
+php artisan horizon:assets
```
+> IMPORTANT: Add the above command to your deployment logic. This way the assets will always be up to date on your staging or production environment.
+
* Configure Laravel Horizon settings file at `config/horizon.php`, please make sure `use` contains `horizon` (see the configuration snippet below).
```
diff --git a/classes/PathHelper.php b/classes/PathHelper.php
index 7cda5a8..75eab04 100644
--- a/classes/PathHelper.php
+++ b/classes/PathHelper.php
@@ -4,39 +4,24 @@
namespace Vdlp\Horizon\Classes;
-use Cms\Classes\Theme;
-use Cms\Facades\Cms;
+use Illuminate\Contracts\Routing\UrlGenerator;
+use Illuminate\Filesystem\Filesystem;
+use Throwable;
final class PathHelper
{
- /**
- * @var Theme|null
- */
- private $theme;
+ private UrlGenerator $urlGenerator;
+ private Filesystem $filesystem;
- public function __construct()
+ public function __construct(UrlGenerator $urlGenerator, Filesystem $filesystem)
{
- $this->theme = Theme::getActiveTheme();
- }
-
- private function hasActiveTheme(): bool
- {
- return $this->theme !== null;
+ $this->urlGenerator = $urlGenerator;
+ $this->filesystem = $filesystem;
}
public function getAssetsPath(?string $path = null): string
{
- if (!$this->hasActiveTheme()) {
- return (string) $path;
- }
-
- $assetsPath = $this->theme->getPath(
- $this->theme->getDirName()
- . DIRECTORY_SEPARATOR
- . 'assets'
- . DIRECTORY_SEPARATOR
- . 'horizon'
- );
+ $assetsPath = plugins_path('vdlp/horizon/assets');
if ($path !== null) {
$assetsPath .= DIRECTORY_SEPARATOR . ltrim($path, DIRECTORY_SEPARATOR);
@@ -47,11 +32,7 @@ public function getAssetsPath(?string $path = null): string
public function getAssetsUrlPath(?string $path = null): string
{
- if (!$this->hasActiveTheme()) {
- return (string) $path;
- }
-
- $assetsUrlPath = Cms::url('/themes/' . $this->theme->getDirName() . '/assets/horizon');
+ $assetsUrlPath = $this->urlGenerator->asset('plugins/vdlp/horizon/assets');
if ($path !== null) {
$assetsUrlPath .= '/' . ltrim($path, '/');
@@ -59,4 +40,16 @@ public function getAssetsUrlPath(?string $path = null): string
return $assetsUrlPath;
}
+
+ public function assetsAreCurrent(): bool
+ {
+ $publishedPath = $this->getAssetsPath('mix-manifest.json');
+ $vendorPath = base_path('vendor/laravel/horizon/public/mix-manifest.json');
+
+ try {
+ return $this->filesystem->get($publishedPath) === $this->filesystem->get($vendorPath);
+ } catch (Throwable $exception) {
+ return false;
+ }
+ }
}
diff --git a/composer.json b/composer.json
index 66a3e3c..3550ee3 100644
--- a/composer.json
+++ b/composer.json
@@ -20,13 +20,12 @@
],
"license": "GPL-2.0-only",
"require": {
- "php": ">=7.1",
+ "php": "^7.4 || ^8.0",
"ext-pcntl": "*",
"ext-posix": "*",
"ext-redis": "*",
"laravel/horizon": "^3.0",
"composer/installers": "^1.0"
-
},
"archive": {
"exclude": [
diff --git a/console/InstallCommand.php b/console/InstallCommand.php
new file mode 100644
index 0000000..d861d02
--- /dev/null
+++ b/console/InstallCommand.php
@@ -0,0 +1,29 @@
+signature = 'horizon:install';
+ $this->description = 'Install all of the Horizon resources';
+
+ parent::__construct();
+ }
+
+ public function handle(): void
+ {
+ $this->comment('Publishing Horizon Assets...');
+ $this->callSilent('vendor:publish', ['--tag' => 'horizon-assets']);
+
+ $this->comment('Publishing Horizon Configuration...');
+ $this->callSilent('vendor:publish', ['--tag' => 'horizon-config']);
+
+ $this->info('Horizon scaffolding installed successfully.');
+ }
+}
diff --git a/console/PushExampleJobs.php b/console/PushExampleJobsCommand.php
similarity index 91%
rename from console/PushExampleJobs.php
rename to console/PushExampleJobsCommand.php
index 0871ad6..48c99f6 100644
--- a/console/PushExampleJobs.php
+++ b/console/PushExampleJobsCommand.php
@@ -8,7 +8,7 @@
use October\Rain\Support\Str;
use Vdlp\Horizon\Jobs\Example;
-final class PushExampleJobs extends Command
+final class PushExampleJobsCommand extends Command
{
public function __construct()
{
diff --git a/jobs/Example.php b/jobs/Example.php
index 5d137a4..95f13a0 100644
--- a/jobs/Example.php
+++ b/jobs/Example.php
@@ -12,8 +12,10 @@
final class Example implements ShouldQueue
{
- use Dispatchable, Queueable;
- private $fooBar;
+ use Dispatchable;
+ use Queueable;
+
+ private string $fooBar;
public function __construct(string $fooBar)
{
@@ -21,7 +23,6 @@ public function __construct(string $fooBar)
}
/**
- * @param LoggerInterface $log
* @throws Exception
*/
public function handle(LoggerInterface $log): void
diff --git a/listeners/SendNotification.php b/listeners/SendNotification.php
index 9c4f6a9..465e026 100644
--- a/listeners/SendNotification.php
+++ b/listeners/SendNotification.php
@@ -11,15 +11,8 @@
final class SendNotification
{
- /**
- * @var Horizon\Lock
- */
- private $lock;
-
- /**
- * @var Mailer
- */
- private $mailer;
+ private Horizon\Lock $lock;
+ private Mailer $mailer;
public function __construct(Horizon\Lock $lock, Mailer $mailer)
{
@@ -46,11 +39,14 @@ public function handle(Horizon\Events\LongWaitDetected $event): void
'seconds' => $notification->seconds,
];
- $this->mailer->send('vdlp.horizon::mail.long-wait-detected', $data, static function (Message $message) {
- $message
- ->to(Horizon\Horizon::$email)
- ->subject(config('app.name') . ': Long Queue Wait Detected');
- });
+ $this->mailer->send(
+ 'vdlp.horizon::mail.long-wait-detected',
+ $data,
+ static function (Message $message): void {
+ $message
+ ->to(Horizon\Horizon::$email)
+ ->subject(config('app.name') . ': Long Queue Wait Detected');
+ });
}
}
}
diff --git a/models/Settings.php b/models/Settings.php
index c1b8cb1..af7f499 100644
--- a/models/Settings.php
+++ b/models/Settings.php
@@ -13,8 +13,8 @@
final class Settings extends Model
{
public $implement = ['System.Behaviors.SettingsModel'];
- public $settingsCode = 'vdlp_horizon_settings';
- public $settingsFields = 'fields.yaml';
+ public string $settingsCode = 'vdlp_horizon_settings';
+ public string $settingsFields = 'fields.yaml';
public function isMailNotificationEnabled(): bool
{
diff --git a/routes.php b/routes.php
index bb5d000..b636b3a 100644
--- a/routes.php
+++ b/routes.php
@@ -2,18 +2,42 @@
declare(strict_types=1);
+use Illuminate\Contracts\Routing\ResponseFactory;
+use Illuminate\Http\Request;
use Illuminate\Routing\Router;
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
use Vdlp\Horizon\Classes\PathHelper;
/** @var Router $router */
$router = resolve(Router::class);
-$router->group(['middleware' => ['web']], static function () use ($router) {
- $router->get('/vendor/horizon/img/horizon.svg', static function () {
- $helper = new PathHelper;
+/** @var PathHelper $pathHelper */
+$pathHelper = resolve(PathHelper::class);
- return response()->download($helper->getAssetsPath('img/horizon.svg'), 'horizon.svg', [
+$router->group(['middleware' => ['web']], static function () use ($router, $pathHelper): void {
+ $router->get('/vendor/horizon/img/horizon.svg', static function () use ($pathHelper): BinaryFileResponse {
+ /** @var ResponseFactory $factory */
+ $factory = resolve(ResponseFactory::class);
+
+ return $factory->download($pathHelper->getAssetsPath('img/horizon.svg'), 'horizon.svg', [
'Content-Type' => 'image/svg+xml',
]);
});
});
+
+if (!$pathHelper->assetsAreCurrent()) {
+ $router->group([
+ 'domain' => config('horizon.domain'),
+ 'prefix' => config('horizon.path'),
+ 'middleware' => config('horizon.middleware', 'web'),
+ ], static function () use ($router): void {
+ $router->get('/{anything?}', static function (Request $request): string {
+ if (Laravel\Horizon\Horizon::check($request)) {
+ return 'The published Horizon assets are not up-to-date with the installed version. '
+ . 'To update, run:
php artisan horizon:assets
';
+ }
+
+ abort(403);
+ })->where('anything', '(.*)');
+ });
+}
diff --git a/serviceproviders/HorizonServiceProvider.php b/serviceproviders/HorizonServiceProvider.php
index 2556490..a880ab6 100644
--- a/serviceproviders/HorizonServiceProvider.php
+++ b/serviceproviders/HorizonServiceProvider.php
@@ -4,7 +4,6 @@
namespace Vdlp\Horizon\ServiceProviders;
-use Cms\Classes\Theme;
use Laravel\Horizon;
use Laravel\Horizon\HorizonServiceProvider as HorizonServiceProviderBase;
use Vdlp\Horizon\Listeners\SendNotification;
@@ -14,7 +13,7 @@ final class HorizonServiceProvider extends HorizonServiceProviderBase
public function defineAssetPublishing(): void
{
$this->publishes([
- HORIZON_PATH . '/public' => $this->getAssetPath(),
+ HORIZON_PATH . '/public' => plugins_path('vdlp/horizon/assets'),
], 'horizon-assets');
}
@@ -31,20 +30,4 @@ protected function registerResources(): void
{
$this->loadViewsFrom(plugins_path('vdlp/horizon/views'), 'horizon');
}
-
- private function getAssetPath(): string
- {
- /** @var Theme $theme */
- $theme = Theme::getActiveTheme();
-
- if ($theme === null) {
- return '';
- }
-
- return $theme->getPath(implode(DIRECTORY_SEPARATOR, [
- $theme->getDirName(),
- 'assets',
- 'horizon',
- ]));
- }
}
diff --git a/updates/version.yaml b/updates/version.yaml
index d1a96ae..12d7820 100644
--- a/updates/version.yaml
+++ b/updates/version.yaml
@@ -1 +1,2 @@
1.0.0: "First version of Vdlp.Horizon"
+2.0.0: "Removed the dependency of the October CMS module. Moved Horizon Assets. See CHANGELOG for more details."
diff --git a/views/layout.blade.php b/views/layout.blade.php
index 5dac5eb..b412e11 100644
--- a/views/layout.blade.php
+++ b/views/layout.blade.php
@@ -1,4 +1,4 @@
-
+