fooino/core
A lightweight core package for Laravel/PHP projects, bundling shared utilities, service providers, and sensible configuration defaults. It simplifies common setup tasks and provides a stable foundation for Fooino-based applications, helping you focus on building features instead of boilerplate.
composer require <vendor>/<package> and confirm the package registers its constants eagerly. Sentinel constants are typically exposed through a files autoload entry in the package's composer.json, so if the constants are undefined after install, run composer dump-autoload before debugging anything else.src/constants.php, src/Sentinel.php, or similar). v1.6.0 adds UNKNOWN, INVALID, UNDEFINED, NOT_FOUND, and HIDDEN as global constants — verify their exact names, namespace (global vs. class constants), and underlying values before writing code against them.null/false/'' returns from a service or repository with a sentinel. A cache or lookup method that currently returns null on a miss can return NOT_FOUND instead, letting callers distinguish "no result" from "not queried yet" (UNKNOWN) or "result was filtered" (HIDDEN).Boundary returns instead of null. Use sentinels at the edges of your application (repositories, HTTP clients, cache wrappers) and convert to null/exceptions at the domain boundary. This keeps null meaningful internally while giving callers richer information at the edge.
public function find(string $key): mixed
{
$hit = $this->store->get($key);
return $hit === null ? NOT_FOUND : $hit;
}
Guard clauses over nested conditionals. A match (true) or early-return chain reads well with sentinels because each constant maps to a distinct branch:
return match ($result) {
NOT_FOUND => $this->missingResponse(),
INVALID => $this->validationResponse(),
HIDDEN => $this->forbiddenResponse(),
default => $this->okResponse($result),
};
Serialization control in API resources. HIDDEN is naturally an instruction to omit a key rather than emit a value. Handle it in your JsonResource/transformer so it never leaks into the payload:
public function toArray($request): array
{
return collect($this->fields)
->reject(fn ($v) => $v === HIDDEN)
->all();
}
Validation and parsing layers. Map a failed parse to INVALID and an unparseable/unknown shape to UNDEFINED, keeping the two distinct so you can log them differently (client error vs. upstream contract violation).
Config and feature-flag defaults. UNKNOWN is useful for tri-state flags where false would wrongly imply "explicitly disabled" — e.g. an entitlement check that hasn't been resolved yet.
Testing. Assert with assertSame(NOT_FOUND, $result) rather than assertEquals, and prefer factory helpers or fixture methods that return the constants so refactors stay centralized.
Optional wrapping. If you need behaviour on sentinels, wrap them in a small enum or value object with isSentinel(): bool, and keep the raw constants for comparisons. This gives you static analysis and IDE completion without giving up the cheap global checks.
NOT_FOUND or HIDDEN, you will get a fatal redeclaration error or silently pick up the wrong value depending on load order. Grep your codebase and vendor/ for define('NOT_FOUND' and similar before upgrading. Guard with defined() in bootstrap code that might load twice.==, or in_array() without the strict flag, will produce false positives against 0, '', or false. Always use === and in_array($v, [...], true).if ($value) evaluates true — a HIDDEN or INVALID value will be treated as valid data. Never rely on truthiness for sentinel checks.null or a string state at the persistence boundary; otherwise your data layer fills with magic strings that only this package understands.json_encode, and Collection::toArray() all pass scalars through untouched, so sentinels will serialize. If you rely on HIDDEN for omission, enforce it in the transformer, not in the model.files, they are available in config files, service providers, and migrations — but not in code that runs before Composer's autoloader (e.g. some artisan bootstrap paths, or PHPUnit bootstrap files that bypass vendor/autoload.php).var_dump/dd, so logs lose intent. Log the constant name explicitly ('lookup' => 'NOT_FOUND') or wrap in a small enum when the distinction matters for observability.@var docblocks or a stub file, or expose them through a class constant that mirrors the global so your analysis baseline stays clean.How can I help you explore Laravel packages today?