Skip to content

Commit 5aecf91

Browse files
committed
dependencies prototype documentation
1 parent 0c1e478 commit 5aecf91

File tree

4 files changed

+414
-4
lines changed

4 files changed

+414
-4
lines changed

.gitignore

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,8 @@ node_modules
1010
### Plugins ###
1111
thesaurex
1212
/db
13-
/app/Plugins/
13+
/app/Plugins/*
14+
!/app/Plugins/PLUGIN.md
1415

1516

1617
## PHPUnit

app/Plugins/PLUGIN.md

Lines changed: 340 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,340 @@
1+
# Plugins
2+
3+
Plugins are a powerful way to extend the functionality of your application without modifying the core codebase. They allow you to add new features without the need to modify the core application, making it easier to integrate custom functionality for different projects.
4+
5+
## Plugin Structure
6+
7+
Each plugin should be placed in the `app/Plugins/` directory with the following structure:
8+
9+
```
10+
app/Plugins/YourPlugin/
11+
├── App/
12+
│ ├── info.xml # Plugin metadata
13+
│ ├── permissions.json # (Optional) Plugin permissions
14+
│ └── role-presets.json # (Optional) Role presets
15+
├── composer.json # PHP dependencies
16+
├── package.json # JavaScript dependencies
17+
├── routes/ # (Optional) Plugin routes
18+
├── src/ # Frontend source files
19+
├── Scopes/ # (Optional) Model scopes
20+
├── js/
21+
│ └── script.js # Compiled plugin script
22+
└── CHANGELOG.md # Version history
23+
```
24+
25+
## Features
26+
27+
### PHP Dependencies
28+
29+
Plugins can declare their own PHP dependencies using a standard `composer.json` file. The main application uses the [Composer Merge Plugin](https://github.com/wikimedia/composer-merge-plugin) to automatically discover and install all plugin dependencies when you run `composer install` or `composer update`.
30+
31+
#### How It Works
32+
33+
1. **Each plugin has its own `composer.json`** in its root directory
34+
2. **Dependencies are automatically merged** into the main application's composer.json
35+
3. **All packages are installed** in the main application's `vendor/` directory
36+
4. **Composer handles version resolution** automatically
37+
38+
#### Creating a Plugin composer.json
39+
40+
Create a `composer.json` file in your plugin's root directory:
41+
42+
```json
43+
{
44+
"name": "spacialist-plugin/your-plugin-name",
45+
"description": "Description of your plugin",
46+
"type": "library",
47+
"license": "MIT",
48+
"authors": [
49+
{
50+
"name": "Your Name",
51+
"email": "your.email@example.com"
52+
}
53+
],
54+
"require": {
55+
"php": ">=8.2.0",
56+
"guzzlehttp/guzzle": "^7.0",
57+
"monolog/monolog": "^3.0"
58+
},
59+
"autoload": {
60+
"psr-4": {
61+
"App\\Plugins\\YourPluginName\\": "App/"
62+
}
63+
}
64+
}
65+
```
66+
67+
#### Important Notes
68+
69+
- **Package naming**: Use the format `spacialist-plugin/your-plugin-name` (kebab-case)
70+
- **PHP version**: Must be compatible with the main application (>=8.2.0)
71+
- **Autoloading**: Follow PSR-4 standard with namespace `App\Plugins\YourPluginName\`
72+
- **Version constraints**: Use semantic versioning (e.g., `^7.0`, `~2.5`, `>=1.0.0`)
73+
74+
#### Installing Dependencies
75+
76+
After creating or modifying a plugin's `composer.json`, run:
77+
78+
```bash
79+
composer update
80+
```
81+
82+
This will:
83+
- Discover all plugin `composer.json` files
84+
- Merge their dependencies
85+
- Resolve version conflicts
86+
- Install all packages to `vendor/`
87+
88+
#### Version Conflicts
89+
90+
If multiple plugins require different versions of the same package, Composer will:
91+
1. Attempt to find a compatible version that satisfies all constraints
92+
2. Display an error if no compatible version exists
93+
3. You'll need to update plugin requirements to compatible versions
94+
95+
#### Example: Adding a New Dependency
96+
97+
**Before:**
98+
```json
99+
{
100+
"require": {
101+
"php": ">=8.2.0"
102+
}
103+
}
104+
```
105+
106+
**After:**
107+
```json
108+
{
109+
"require": {
110+
"php": ">=8.2.0",
111+
"symfony/yaml": "^6.0",
112+
"league/csv": "^9.8"
113+
}
114+
}
115+
```
116+
117+
Then run `composer update` to install the new packages.
118+
119+
### Metadata File (info.xml)
120+
121+
The `App/info.xml` file contains essential plugin metadata:
122+
123+
```xml
124+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
125+
<info>
126+
<name>YourPlugin</name>
127+
<title>Your Plugin Title</title>
128+
<description>Description of what your plugin does</description>
129+
<version>1.0.0</version>
130+
<licence>MIT</licence>
131+
<authors>
132+
<author>Your Name</author>
133+
</authors>
134+
<compatibility>
135+
<spacialist>0.12</spacialist>
136+
<php>8.2</php>
137+
</compatibility>
138+
<dependencies>
139+
<!-- List other plugins this plugin depends on -->
140+
</dependencies>
141+
<permissions>
142+
<!-- Declare what features your plugin uses -->
143+
<!-- <client /> -->
144+
<!-- <migration /> -->
145+
<!-- <routes /> -->
146+
<!-- <public /> -->
147+
</permissions>
148+
<accesspoints>
149+
<!-- Define custom routes/pages -->
150+
<!-- <accesspoint id="custom-page" label="Custom Page" path="/custom" /> -->
151+
</accesspoints>
152+
<scopes>
153+
<!-- Register model scopes -->
154+
<!-- <scope src="YourScope.php" on="App\Entity" /> -->
155+
</scopes>
156+
<attributes>
157+
<!-- Register custom attributes -->
158+
</attributes>
159+
</info>
160+
```
161+
162+
#### Key Fields
163+
164+
- **name**: Internal identifier (must match directory name)
165+
- **title**: Display name shown in UI
166+
- **version**: Semantic version (major.minor.patch)
167+
- **compatibility**: Minimum required versions
168+
- **permissions**: Required features (migration, routes, etc.)
169+
170+
### Permissions
171+
172+
Define plugin-specific permissions in `App/permissions.json`:
173+
174+
```json
175+
{
176+
"plugin_group": [
177+
{
178+
"name": "create",
179+
"display_name": "Create items",
180+
"description": "Allow creating new items"
181+
},
182+
{
183+
"name": "delete",
184+
"display_name": "Delete items",
185+
"description": "Allow deleting items"
186+
}
187+
]
188+
}
189+
```
190+
191+
Permissions are automatically registered during plugin installation.
192+
193+
### Routes
194+
195+
Create custom API routes in `routes/api.php`:
196+
197+
```php
198+
<?php
199+
200+
use Illuminate\Support\Facades\Route;
201+
202+
Route::middleware('auth:sanctum')->group(function () {
203+
Route::get('/plugin-data', 'App\Plugins\YourPlugin\App\Controllers\DataController@index');
204+
Route::post('/plugin-data', 'App\Plugins\YourPlugin\App\Controllers\DataController@store');
205+
});
206+
```
207+
208+
### Migrations
209+
210+
Place database migrations in `App/Migrations/`:
211+
212+
```php
213+
<?php
214+
215+
use App\MigrationBase;
216+
use Illuminate\Database\Schema\Blueprint;
217+
218+
return new class extends MigrationBase
219+
{
220+
public function up()
221+
{
222+
$this->schema()->create('plugin_table', function (Blueprint $table) {
223+
$table->id();
224+
$table->string('name');
225+
$table->timestamps();
226+
});
227+
}
228+
229+
public function down()
230+
{
231+
$this->schema()->dropIfExists('plugin_table');
232+
}
233+
};
234+
```
235+
236+
### Model Scopes
237+
238+
Add global scopes in `Scopes/` and register them in `info.xml`:
239+
240+
```php
241+
<?php
242+
243+
namespace App\Plugins\YourPlugin\Scopes;
244+
245+
use Illuminate\Database\Eloquent\Builder;
246+
use Illuminate\Database\Eloquent\Model;
247+
use Illuminate\Database\Eloquent\Scope;
248+
249+
class YourScope implements Scope
250+
{
251+
public function apply(Builder $builder, Model $model)
252+
{
253+
// Apply your scope logic
254+
}
255+
}
256+
```
257+
258+
Register in `info.xml`:
259+
```xml
260+
<scopes>
261+
<scope src="YourScope.php" on="App\Entity" />
262+
</scopes>
263+
```
264+
265+
### Frontend Integration
266+
267+
Build your frontend with Vite and export it to `js/script.js`. The plugin system will automatically load this file when the plugin is activated.
268+
269+
### Changelog
270+
271+
Maintain a `CHANGELOG.md` file to track version history:
272+
273+
```markdown
274+
# Changelog
275+
276+
## Version 1.1.0 - 2026-02-09
277+
### Added
278+
- New feature X
279+
- Support for Y
280+
281+
### Fixed
282+
- Bug in Z
283+
284+
## Version 1.0.0 - 2026-01-01
285+
- Initial release
286+
```
287+
288+
## Development Workflow
289+
290+
1. **Create plugin directory** in `app/Plugins/YourPlugin`
291+
2. **Add composer.json** with your PHP dependencies
292+
3. **Add package.json** with your JavaScript dependencies
293+
4. **Create info.xml** with plugin metadata
294+
5. **Run composer update** to install PHP dependencies
295+
6. **Run npm install** to install JavaScript dependencies
296+
7. **Develop your plugin** (backend, frontend, migrations, etc.)
297+
8. **Build frontend**: `npm run build`
298+
9. **Test your plugin** in development mode
299+
10. **Install via admin interface** when ready
300+
301+
## Best Practices
302+
303+
- **Use semantic versioning** for your plugin versions
304+
- **Document breaking changes** in CHANGELOG.md
305+
- **Specify minimum PHP/Spacialist versions** in info.xml
306+
- **Use PSR-4 autoloading** for PHP classes
307+
- **Keep dependencies minimal** to avoid conflicts
308+
- **Test with different plugin combinations**
309+
- **Provide clear installation instructions**
310+
311+
## Troubleshooting
312+
313+
### Dependency Conflicts
314+
315+
If you encounter version conflicts:
316+
317+
```bash
318+
composer update --with-all-dependencies
319+
```
320+
321+
Check which plugins require conflicting versions:
322+
```bash
323+
composer why vendor/package
324+
composer why-not vendor/package 2.0
325+
```
326+
327+
### Autoloading Issues
328+
329+
If classes aren't found after adding to composer.json:
330+
331+
```bash
332+
composer dump-autoload
333+
```
334+
335+
### Plugin Not Detected
336+
337+
1. Check that `info.xml` is in `App/` directory
338+
2. Verify XML is valid
339+
3. Ensure directory name matches `<name>` in info.xml
340+
4. Refresh plugin state in admin interface

composer.json

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"spatie/laravel-permission": "^6.16.0",
2929
"spatie/laravel-searchable": "^1.13",
3030
"tecnickcom/tcpdf": "^6.8.2",
31-
"wapmorgan/unified-archive": "^1.1.10"
31+
"wapmorgan/unified-archive": "^1.1.10",
32+
"wikimedia/composer-merge-plugin": "^2.1"
3233
},
3334
"require-dev": {
3435
"beyondcode/laravel-dump-server": "^2.0",
@@ -58,6 +59,15 @@
5859
"extra": {
5960
"laravel": {
6061
"dont-discover": []
62+
},
63+
"merge-plugin": {
64+
"include": [
65+
"app/Plugins/*/composer.json"
66+
],
67+
"recurse": true,
68+
"replace": false,
69+
"ignore-duplicates": false,
70+
"merge-dev": false
6171
}
6272
},
6373
"scripts": {
@@ -75,6 +85,9 @@
7585
"config": {
7686
"preferred-install": "dist",
7787
"sort-packages": true,
78-
"optimize-autoloader": true
88+
"optimize-autoloader": true,
89+
"allow-plugins": {
90+
"wikimedia/composer-merge-plugin": false
91+
}
7992
}
8093
}

0 commit comments

Comments
 (0)