ui5:doctor
since 5.0php artisan ui5:doctor checks your checkout and tells you what is wrong and how to fix it.It reads the UI5 projects your modules resolve, their manifests and yamls, the resource bundles and .ui5-sources.php. It never writes a file and never touches a database, so you can run it any time: right after a scaffold, when an app misbehaves, and in CI before a tag.
php artisan ui5:doctorReading the report
Findings are grouped by severity. Each line names the rule, the subject (a namespace, a file or a key), what is wrong, and after the dash, the fix:
Errors
core.W1 com.acme.offers: sap.f is in webapp/manifest.json but not in ui5-dist.yaml — add `- name: sap.f` under framework.libraries in ui5-dist.yaml
Warnings
core.W4 ../ui5-offers/webapp/i18n/i18n_de.properties: save is missing; other locales of the bundle have it — add save to i18n_de.properties
Notices
core.W2 com.acme.offers: resolved by the workspace strategy from ../ui5-offers
Skipped
core.W3 skipped: no workspace or self-contained app with a Component.ts or Component.js
5 rules run: 1 error, 1 warning, 1 notice, 1 skipped.| Severity | Means | Exit code |
|---|---|---|
| Error | Something is broken now. | 1 |
| Warning | A fault that will bite later, such as the wrong language on screen. | 0 |
| Notice | Worth knowing while you debug. A notice may come without a fix. | 0 |
| Skipped | The rule could not look, and says why. A skip is never a pass. | 0 |
The command runs every rule, every time. There are no options to pick rules.
What Core checks
| Rule | Checks | Severity |
|---|---|---|
| core.W1 | Every sap.* library in an app's webapp/manifest.json is declared in its ui5.yaml, and in ui5-dist.yaml and ui5-coverage.yaml where those exist. The two places | Error |
| core.W2 | Every entry in .ui5-sources.php points to a UI5 project (ui5.yaml, and webapp/manifest.json for an app), and the file stays out of git. For each project, a notice names the strategy that resolved it. Workspace links | Error, Notice |
| core.W3 | An app's component calls LaravelUi5.init(this). Without it the shell does not mount, and writes miss their CSRF handshake. Frontend | Error |
| core.W4 | A key in one locale file of a bundle (i18n_en, i18n_de, …) is in all of them. Keys missing from the base file are one notice per file, since a minimal base bundle can be deliberate. | Warning, Notice |
| core.W5 | Bundles hold no lone surrogate (shown as �), no key whose {N} placeholders differ between locales, and no key defined twice in one file. A file the server cannot read is an error. | Warning, Error |
Core reads the projects you edit: workspace apps and libraries, and self-contained apps. A package installed through Composer carries built resources. Its fix belongs in its source project.
The two places
A UI5 library has to be declared in two places. manifest.json drives what the app loads. ui5.yaml, together with the sibling ui5-dist.yaml and ui5-coverage.yaml, drives what the tooling resolves. A library declared in the manifest only fails at runtime with failed to load 'library.js', and the message does not say which declaration is missing. core.W1 does: it names the library and the yaml.
The Easy UI5 generator scaffolds sap.ui.core and sap.m only. When your app renders a dashboard, add sap.f, and sap.ui.integration for integration cards, in both places (Ui5App).
Workspace links
.ui5-sources.php maps a module to the UI5 project on your disk (the workspace strategy). An entry whose directory is missing does not fail. The module quietly resolves through its package instead, and serves its built resources rather than your source. core.W2 reports that entry.
The file never belongs in git. It describes this checkout. In another one, a colleague's or CI's, its links point nowhere. If the module has no built resources to fall back to, the application then cannot build its registry at all. core.W2 reports a checked-in file as an error and a file that is neither checked in nor ignored as a warning. ui5:app and ui5:lib add it to .gitignore when they create it; in an older host, add it yourself:
.ui5-sources.phpWhen the registry does not load, ui5:doctor still runs. It reports the failure as an error of its own and runs every rule without projects. The file rules skip, and core.W2 still reads .ui5-sources.php, which is where the cause usually is.
In CI
Run it as a step before you tag. A finding with severity Error fails the step:
php artisan ui5:doctorKeep .ui5-sources.php out of the repository, as above. A pipeline without it has no workspace links, so core.W2 has nothing to check, and the file rules skip the packaged modules.
Adding a rule
A package, or your host, adds rules through the container. A rule implements LaravelUi5\Core\Diagnosis\Contracts\DoctorRuleInterface and is tagged with it:
use LaravelUi5\Core\Diagnosis\Contracts\DoctorRuleInterface;
use LaravelUi5\Core\Diagnosis\DiagnosisContext;
use LaravelUi5\Core\Diagnosis\Finding;
use LaravelUi5\Core\Diagnosis\Outcome;
final class VhostVersionRule implements DoctorRuleInterface
{
public function id(): string
{
return 'host.W1';
}
public function description(): string
{
return "Each app's version matches the @version in the dev vhost.";
}
public function run(DiagnosisContext $context): Outcome
{
if (!is_file(base_path('etc/vhost.conf'))) {
return Outcome::skip('no etc/vhost.conf');
}
$findings = [];
foreach ($context->apps() as $namespace => $project) {
// compare $project->root->getVersion() with the vhost's ProxyPass lines …
}
return Outcome::findings(...$findings);
}
}// AppServiceProvider::register()
$this->app->tag([VhostVersionRule::class], DoctorRuleInterface::class);- The id is
<owner>.W<n>:core,sdk,foundationandplatformbelong to the LaravelUi5 packages,hostto your application. The command refuses a malformed or duplicate id before the first rule runs. - The context carries the registered projects, walked once:
projects,apps(),libraries(). Each one gives itsnamespace(), itsrootartifact,strategyName(),projectRoot()(the directory withui5.yaml, for a workspace project) andsourcePath(). Anything else a rule needs comes through its constructor. - The outcome is
Outcome::pass(),Outcome::finding($f),Outcome::findings(...$f)orOutcome::skip($reason). A finding is built withFinding::error()orFinding::warning(), which both require a fix, or withFinding::notice(), where the fix is optional. - Tag it unconditionally. A rule that does not apply to a system answers
pass()orskip(). - Read only. A rule writes no file and touches no database. A check that needs the database is an installation check, not a diagnosis of the checkout.