Skip to content

Commit

Permalink
Improve developer docs (#174)
Browse files Browse the repository at this point in the history
* improve developer documentation

* finishing touches

* fix typo
  • Loading branch information
recursivetree authored Mar 28, 2024
1 parent 71569de commit 25c4f68
Show file tree
Hide file tree
Showing 8 changed files with 114 additions and 19 deletions.
5 changes: 3 additions & 2 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@

This dockerfile is one of many out there to get `mkdocs` up and running, quickly.

Build with: `docker build -t eveseat/docs .`.
Run with: `docker run -d --rm -p 8000:8000 --name docs -v ${PWD}:/docs eveseat/docs` from the projects root.
In the project root:
- Build with: `docker build -t eveseat/docs docker`.
- Run with: `docker run -d --rm -p 8000:8000 --name docs -v ${PWD}:/docs eveseat/docs`.
6 changes: 6 additions & 0 deletions docs/community_packages.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ sudo -H -u www-data bash -c 'php artisan config:cache'
sudo -H -u www-data bash -c 'php artisan seat:cache:clear'
```

- *Seed schedule* so that new and missing commands get added to your schedule:

```bash
sudo -H -u www-data bash -c 'php /var/www/seat/artisan db:seed --class=Seat\\Services\\Database\\Seeders\\PluginDatabaseSeeder'
```

- Bring your application *live* and back out of maintenance mode:

```bash
Expand Down
21 changes: 14 additions & 7 deletions docs/developer_guides/developer_installation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,17 @@

# Developer Installation

Since SeAT 4 and including SeAT 5, starting with Docker build 4.1.0, spawning a development environment has been made easier.
You can use the same image as of production environment - either you're working on core packages or third party ones.
This document describes how to set up a development environment for both core package and third party package development.
The easiest way to set up a development environment is to use docker. You can use the same image as in a production environment.

## General
For development, plugins and the seat core are treated the same. When working on the core, you install a core package like
any other plugin. This is also how core packages are implemented: Internally they are also just a plugin, only that they
are considered the core and that other plugins build on top of them.

The SeAT docker image is built in a way to prefer development installations of packages over plugins from `.env` and the core. While the docker image always downloads and installs
the core packages, when it finds a local development install of a core package, it uses that over the latest version from packagist.

## Setup Process

First, start with [standard installation](../installation/docker_installation.md) to get a working environment.

Expand All @@ -14,10 +21,8 @@ It is mounted readonly, and you can store your development sources in it.

To make things easier, we recommend you keep vendor path convention to split your sources across every single package you want to play with.

Developing plugins and core packages doesn't differ at all, modules installed in the `packages` directory always take priority.
In the case of core modules, this means the version from `packages` and not the version provided by the docker container will be used.

## Overrider
### Overrider
In the next step, we need to let laravel, the php framework used by seat, know that our plugin is there.

The image has been designed to look for a file called `override.json` inside `packages` directory.
When it is found, it will be merged together with standard `composer.json` file from `eveseat/seat` package.
Expand Down Expand Up @@ -53,6 +58,8 @@ When your container will start, mapping from `autoload` property in your `overri

Please note that there is currently no way to install dependencies with the package override.

When installing already existing packages (e.g. a core package), you can find all required autoloads and service providers in it's `composer.json` file.

## Teach things by example

As an example, let's say I want to make a new feature in web core package, I'll spawn an `eveseat` directory at root `packages` directory, followed by a clone from `eveseat/web` git repository.
Expand Down
37 changes: 37 additions & 0 deletions docs/developer_guides/development_tips.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ No doubt, there are no limits to what code you can write, how you structure it a
- Avoid altering core tables, especially introducing relationship - this might break core migrations. Prefer to use observer if you need to maintain your data across core models.
- If you need an API or something the SeAT core doesn't provide, consider contributing it. The SeAT core is not set in stone.
- Scope your routes: For example all routes from the seat core start with `seatcore`like this: `seatcore::my.route.to.someting`. You should follow a similar format: `seat<plugin name>::<route>`
- Use a [schedule seeder](package_development.md#jobs--schedules) for adding commands to the schedule. Compared to migrations, this has the advantage that accidentally deleted commands will be added back automatically on the next restart.
- For all your model, extend from `\Seat\Services\Models\ExtensibleModel` instead of the standard laravel `Model`. They are functionally equivalent, but `ExtensibleModel` allows [injectable relations](#injectable-relations).

## Model Observers

Expand All @@ -30,3 +32,38 @@ For example, should a `User` model get deleted, the `deleted` event will get fir
Examples of where this may be interesting could be if you need to have cleanup code for tables that your package includes.

For more information, checkout the Laravel documentation on [Eloquent Observers](https://laravel.com/docs/10.x/eloquent#observers).

## Useful SeAT-Specific Features
### Deferred Migrations
Sometimes you might want to run some business logic in a migration. For example, when adding a new column, you might want to fill that column with a computation that is part of your business logic.
If you have all the logic inside your migration class, and you don't depend on any other application code, you are good. However, when your migration depends on application code, it is likely that
you run into issues later down the line. Your business logic probably assumes that all your migrations have run. However, when calling business logic from migrations, this is not guaranteed.
Later migrations have not yet run, meaning you are likely to run into issues.

Seat offers a solution to this: Deferred Migrations. These are functions that can be scheduled in a migration and that run after all other migrations have finished.
In your migration, you can schedule a deferred migration like this:

```php
\Seat\Services\Facades\DeferredMigration::schedule(function (){
// this closure runs after all migrations have finished. It is save to call business logic from here.
});
```

### Injectable Relations
Cross-package interaction is at the heart of SeAT. For example, plugins use the ESI data pulled by `eveapi`. However, there is one issue: While a plugin can always assume that `eveapi` is there,
this is not possible the other way around. The seat core can run without any plugin. This implies that the plugin can have a relation pointing from a plugin model to a core model, but not the other
way around.

In SeAT, there is a system of injectable relations that helps with this. In short, to any model extending from `\Seat\Services\Models\ExtensibleModel`, you can attach relations similar to how you
attach observers.

First, you create a model extension class containing the relations you want to add to the base model. This extension class should extend from the base model.

Second, you register the extension classes in your service provider's boot method like this:
```php
BaseModel::injectRelationsFrom(ModelExtension::class);
```

The relations defined in the model extension class should now be usable on the base model.

Even though the model extension extends from the base class and behaves the same for the most part, you should always use the base class in your code, as otherwise observers aren't working properly.
9 changes: 3 additions & 6 deletions docs/developer_guides/notifications_implementation.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@

# Developers Guides - Notifications Implementation

!!! warning "Seat 5"
This guide is already updated for seat 5. Older versions of this guide can be found on [github](https://github.com/eveseat/docs/tree/8a33fdb141cb8d5f0733f0a936a06fdffd3781c4).

## Introduction

SeAT is shipped with a built-in notification system which is able to send message across the world to almost any platform.
Expand Down Expand Up @@ -125,13 +122,13 @@ All notifications continue to work without any changes, even though there have b

- Start extending from the platform specific classes instead of `Seat\Notifications\Notifications\AbstractNotification`.
- Discord: extend `Seat\Notifications\Notifications\AbstractDiscordNotification`
- Slack: extend `Seat\Notifications\Notifications\AbstractSlackDiscordNotification`
- Slack: extend `Seat\Notifications\Notifications\AbstractSlackNotification`
- Mail: extend `Seat\Notifications\Notifications\AbstractMailNotification`
- Remove the via method. It moved to the abstract notification class.
- Refactor your public `toX()` method to a protected `populateMessage(Messagetype $message, $notifiable)`. Instead of creating a new message, use the parameter `$message`. The type `Message` must be adjusted depending on your platform:
- Refactor your public `toX()` method to a protected `populateMessage(MessageType $message, $notifiable)`. Instead of creating a new message, use the parameter `$message`. The type `MessageType` must be adjusted depending on your platform:
- discord: `Seat\Notifications\Services\Discord\Messages\DiscordMessage`
- slack: `Illuminate\Notifications\Messages\SlackMessage`
- mail: `Illuminate\Notifications\Messages\MailMessage`
- Consider using the `Seat\Notifications\Traits\NotificationDispatchTool` trait to dispatch notification. It helps to deduplicate the most common logic.

The old plugin structure will stop working in seat 6.
The old notification structure will stop working in seat 6.
45 changes: 45 additions & 0 deletions docs/developer_guides/package_development.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,51 @@ Registering these migrations looks like the following:
$this->loadMigrationsFrom(__DIR__ . '/database/migrations/');
```

## Jobs & Schedules
Many packages need to run certain actions in a regular interval. For example, a mining tax plugin might want to calculate taxes once a day. This can be done with the job queue and the schedule system.

First, create your job containing the logic you want to run on a schedule. You can refer to the [laravel docs](https://laravel.com/docs/10.x/queues) for this.

Next, create an artisan command that launches your job. Again, you can refer to the [laravel docs](https://laravel.com/docs/10.x/artisan) for this.

In a last step, we create a database seeder that adds your command to the schedule. In your `database/seeders/` directory, create a class that extends from `\Seat\Services\Seeding\AbstractScheduleSeeder`.
The required `getSchedules()` function should return an array describing the command you wish to schedule, according to the following format:
```php
public function getSchedules(): array
{
return [
[
'command' => 'horizon:snapshot', // your artisan command
'expression' => '*/5 * * * *', // this is a cron expression describing how often your command should be run
'allow_overlap' => false,
'allow_maintenance' => false,
'ping_before' => null,
'ping_after' => null,
],
[
'command' => 'other:command',
'expression' => '*/5 * * * *',
'allow_overlap' => false,
'allow_maintenance' => false,
'ping_before' => null,
'ping_after' => null,
],
];
}
```

You can let the `getDeprecatedSchedules()` function return an empty array for now.

Lastly, register your seeder in your service provider's `register()` method using
```php
$this->registerDatabaseSeeders(MyScheduleSeeder::class);
```

When you restart the stack, the seeder should add the command to the schedule. For testing, it might also be useful to run the seeder manually using
```
php artisan db:seed --class=Seat\\Services\\Database\\Seeders\\PluginDatabaseSeeder
``
## Releasing the plugin
The usual setup is to host the code on github and distribute the code via [packagist](https://packagist.org/).
When you submit your plugin on packagist, it will be installable like the other plugins by adding `<vendor>/<package>` to the appropriate section of your `.env` file.
Expand Down
4 changes: 3 additions & 1 deletion docs/developer_guides/updating_plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@ SeAT 5 mainly upgrades the php and laravel version as well as all dependencies t

- PHP 8.2: SeAT now runs on php 8.2, enabling new features like enums and better type hinting, but also breaking a few things.
- Route Prefixing: All routes from the seat core start with `seatcore::`. For example, `notifications.integrations.list` turns into `seatcore::notifications.integrations.list`. If your plugin uses routes pointing to the seat core, you will have to update them.
- Notifications: All notifications from SeAT 4 continue to work, but by updating them you can unlock more features like discord pings. See the [notifications guide](notifications_implementation.md) for more details.
- Models: With SeAT 5, the `services` packages starts to ship a `ExtensibleModel` class. Plugins can inject relation into these models, fo example from an eveapi model to a plugin model.
It is recommended that all models start extending from `\Seat\Services\Models\ExtensibleModel`. It is enough to just switch from `MyClass extend Model` to `MyClass extends ExtensibleModel`
- Notifications: All notifications from SeAT 4 continue to work, but by updating them you can enable more features like discord pings. See the [notifications guide](notifications_implementation.md) for more details.
- The `Seat\Eveapi\Jobs\Middleware\WithoutOverlapping` job middleware backport is now provided by laravel and got removed from the SeAT core. Use `Illuminate\Queue\Middleware\WithoutOverlapping` instead. Just swapping the import should be enough, as they are compatible.
- Some, but not all ways of exporting data from DataTables are broken. Just check whether they work and fix if required.
- There are a few minor breaking changes between Laravel 6 and 10:
Expand Down
6 changes: 3 additions & 3 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,11 @@ nav:
- Moons Reporter: user_guides/moons_reporter.md
- Developer Guides:
- Developer Installation: developer_guides/developer_installation.md
- Job Queue Flow: developer_guides/job_queue_flow.md
- Development Tips: developer_guides/development_tips.md
- Notifications Implementation: developer_guides/notifications_implementation.md
- Core Package Breakdown: developer_guides/core_package_breakdown.md
- Package Development: developer_guides/package_development.md
- Development Tips: developer_guides/development_tips.md
- Job Queue Flow: developer_guides/job_queue_flow.md
- Notifications Implementation: developer_guides/notifications_implementation.md
- Updating Plugins: developer_guides/updating_plugins.md
- SeAT API: developer_guides/seat_api.md
- Styling: styling.md
Expand Down

0 comments on commit 25c4f68

Please sign in to comment.