# Service API

> Using the cronjob service from other modules

---

Neighboring modules query the module's state through a stable, read-only facade
(`CronjobService`) instead of its internal services. Check availability first -
the module may not be installed, and the class is only autoloadable when its
<a href="https://github.com/bschwede/wt-cronjob/tree/main/module.php" target="_blank" rel="noopener"><code>module.php</code></a>
 has been loaded:

<div class="highlight"><pre tabindex="0" style="color:#cad3f5;background-color:#24273a;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-php" data-lang="php"><span style="display:flex;"><span><span style="color:#91d7e3;font-weight:bold">&lt;?</span>php
</span></span><span style="display:flex;"><span><span style="color:#c6a0f6">use</span> Schwendinger\Webtrees\Module\Cronjob\Services\CronjobService;
</span></span><span style="display:flex;"><span>
</span></span><span style="display:flex;"><span><span style="color:#c6a0f6">if</span> (class_exists(CronjobService<span style="color:#91d7e3;font-weight:bold">::</span><span style="color:#8aadf4">class</span>) <span style="color:#91d7e3;font-weight:bold">&amp;&amp;</span> CronjobService<span style="color:#91d7e3;font-weight:bold">::</span><span style="color:#8aadf4">isFunctional</span>()) {
</span></span><span style="display:flex;"><span>    <span style="color:#f4dbd6">$status</span> <span style="color:#91d7e3;font-weight:bold">=</span> CronjobService<span style="color:#91d7e3;font-weight:bold">::</span><span style="color:#8aadf4">jobStatus</span>(<span style="color:#a6da95">&#39;mymodule:backup&#39;</span>); <span style="color:#6e738d;font-style:italic">// null = unknown job
</span></span></span><span style="display:flex;"><span>    <span style="color:#f4dbd6">$age</span> <span style="color:#91d7e3;font-weight:bold">=</span> CronjobService<span style="color:#91d7e3;font-weight:bold">::</span><span style="color:#8aadf4">lastTickAge</span>();                <span style="color:#6e738d;font-style:italic">// seconds since last tick
</span></span></span><span style="display:flex;"><span>    <span style="color:#f4dbd6">$listened</span> <span style="color:#91d7e3;font-weight:bold">=</span> CronjobService<span style="color:#91d7e3;font-weight:bold">::</span><span style="color:#8aadf4">listenedEvents</span>();             <span style="color:#6e738d;font-style:italic">// event name =&gt; job names
</span></span></span><span style="display:flex;"><span>}</span></span></code></pre></div>

| Question | Method(s) |
| --- | --- |
| Is the service functional? | `isFunctional()`, `problems()` (codes: `module_disabled`, `not_migrated`, `cron_library_missing`, `tick_stale`) |
| Which features are enabled? | `features()` (`watch`, `pseudo_events`, `route_events`), `watchStatus()` |
| When did the last tick run? | `lastTick()` / `lastTickAge()` - both trigger types (marker file `data/cronjob/tick.last`) |
| Is a job enabled / when did it last run? | `isJobEnabled($name)`, `jobStatus($name)`, `lastRun($name)` - job names are namespaced (`<module>:<name>`) |
| Which events are listened for? | `listenedEvents()`, `listenersFor($event)`; catalogs: `eventCatalog()`, `pseudoEvents()`, `routeEvents()` |
| Actions (the only two) | `runJobNow($name)` (queued at the next tick), `pushEvent($name, $payload)` (event queue) |

Contract: read-only methods never throw when the schema is missing (safe defaults),
descriptions are source strings (never pre-translated), and `lastRun()` deliberately
excludes the job output, which may contain personal data.
