Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
80.95% covered (warning)
80.95%
17 / 21
80.95% covered (warning)
80.95%
17 / 21
CRAP
0.00% covered (danger)
0.00%
0 / 1
Registrar
80.95% covered (warning)
80.95%
17 / 21
80.95% covered (warning)
80.95%
17 / 21
24.05
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 option
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 field
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 fieldSchema
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 nodeSchema
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 collectionSchema
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 node
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 section
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 collection
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 dashboardCard
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 migrations
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 sql
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 assets
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 blockType
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 control
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 templates
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 panelPage
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 css
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 js
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 register
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 routes
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3declare(strict_types=1);
4
5namespace Cosray\Plugin;
6
7use Celema\Container\Entry;
8use Closure;
9use Cosray\Bootstrap;
10use Cosray\Collection;
11use Cosray\Collection\Ref;
12use Cosray\Collection\Schema\Handler as CollectionHandler;
13use Cosray\Config;
14use Cosray\Contract\Block;
15use Cosray\Contract\DashboardCard;
16use Cosray\Field\Schema\Handler as FieldHandler;
17use Cosray\Node\Schema\Handler as NodeHandler;
18use Cosray\Section;
19
20/**
21 * Registration facade handed to each plugin during boot.
22 */
23final class Registrar
24{
25    public function __construct(
26        private readonly Bootstrap $bootstrap,
27        public readonly string $id,
28        public readonly Config $config,
29    ) {}
30
31    /**
32     * An app-config option from this plugin's namespace: option('currency')
33     * reads the '{plugin-id}.currency' settings key. Returns $default when
34     * the app configures nothing — a plugin must work with zero
35     * configuration, so defaults live at the read site, not in the app.
36     */
37    public function option(string $key, mixed $default = null): mixed
38    {
39        return $this->config->get("{$this->id}.{$key}", $default);
40    }
41
42    /** @param class-string<\Cosray\Field\Field> $class */
43    public function field(string $class, string ...$aliases): void
44    {
45        $this->bootstrap->fields()->add($class, ...$aliases);
46    }
47
48    /** @param class-string $attribute */
49    public function fieldSchema(string $attribute, FieldHandler $handler): void
50    {
51        $this->bootstrap->fieldSchemas()->register($attribute, $handler);
52    }
53
54    /** @param class-string $attribute */
55    public function nodeSchema(string $attribute, NodeHandler $handler): void
56    {
57        $this->bootstrap->nodeSchemas()->register($attribute, $handler);
58    }
59
60    /** @param class-string $attribute */
61    public function collectionSchema(string $attribute, CollectionHandler $handler): void
62    {
63        $this->bootstrap->collectionSchemas()->registry()->register($attribute, $handler);
64    }
65
66    /** @param class-string $class */
67    public function node(string $class): void
68    {
69        $this->bootstrap->node($class);
70    }
71
72    public function section(string $name): Section
73    {
74        return $this->bootstrap->section($name);
75    }
76
77    /** @param class-string<Collection> $class */
78    public function collection(string $class): Ref
79    {
80        return $this->bootstrap->collection($class);
81    }
82
83    /** @param class-string<DashboardCard>|DashboardCard $card */
84    public function dashboardCard(string|DashboardCard $card): void
85    {
86        $this->bootstrap->dashboard->add($card);
87    }
88
89    public function migrations(string $dir): void
90    {
91        $this->bootstrap->addMigrations($dir);
92    }
93
94    public function sql(string $dir): void
95    {
96        $this->bootstrap->addSql($dir);
97    }
98
99    /**
100     * Serve prebuilt plugin assets from $dir under
101     * `{panel}/vendor/{pluginId}/...`.
102     */
103    public function assets(string $dir): void
104    {
105        $this->bootstrap->addAssets($this->id, $dir);
106    }
107
108    /**
109     * Add a block type to the default offer list of Blocks fields.
110     *
111     * @param class-string<Block> $class
112     */
113    public function blockType(string $class): void
114    {
115        $this->bootstrap->blockType($class);
116    }
117
118    /**
119     * Register a named custom control rendered by a custom element.
120     * Fields (from any plugin or the project) can then use the name in
121     * their control() definition. Later registrations win, so a plugin
122     * may replace a built-in editor. The module is served from this
123     * plugin's asset dir.
124     */
125    public function control(string $name, string $tag, string $module): void
126    {
127        $this->bootstrap->controls()->register($name, $tag, "{$this->id}/{$module}");
128    }
129
130    /**
131     * Register $dir as template namespace `{pluginId}:` for the given
132     * renderer ('panel' or 'view'). Templates are addressed as
133     * '{pluginId}:template/path'.
134     */
135    public function templates(string $dir, string $renderer = 'panel'): void
136    {
137        $this->bootstrap->addTemplates($this->id, $dir, $renderer);
138    }
139
140    /**
141     * Register a page inside the panel chrome: session, auth and the
142     * panel renderer are applied like for built-in pages. The endpoint
143     * controller should extend Cosray\Controller\Panel\Panel and
144     * return $this->context([...]) so the shell gets its data.
145     *
146     * @param mixed $endpoint route endpoint, e.g. [Controller::class, 'method']
147     */
148    public function panelPage(string $pattern, mixed $endpoint, string $template, string $name): void
149    {
150        $this->bootstrap->addPanelPage($pattern, $endpoint, $template, "{$this->id}.{$name}");
151    }
152
153    /**
154     * A stylesheet loaded on every panel page. App-wide chrome styling
155     * only — field controls load their assets lazily via element
156     * descriptors.
157     */
158    public function css(string $url): void
159    {
160        $this->bootstrap->panelExtras()->addCss($url);
161    }
162
163    /**
164     * A script loaded once per full panel document and NOT re-run across
165     * htmx navigations: write delegated, idempotent listeners — see
166     * "Panel scripts across navigation" in the README.
167     */
168    public function js(string $url, bool $module = true): void
169    {
170        $this->bootstrap->panelExtras()->addJs($url, $module);
171    }
172
173    /**
174     * @param non-empty-string $key
175     * @param class-string|object $value
176     */
177    public function register(string $key, object|string $value): Entry
178    {
179        return $this->bootstrap->addService($key, $value);
180    }
181
182    /** @param Closure(\Celema\Core\App): void $routes */
183    public function routes(Closure $routes): void
184    {
185        $this->bootstrap->addRoutes($routes);
186    }
187}