Fallback chains
A request can list several engines. They are tried in order until one returns content.
How the chain runs
generate() builds the list as the primary engine followed by every fallback
engine, in registration order. For each engine:
- If it returns a non-null string, that result is wrapped in a
GeneratedAvatarand returned immediately. - If it returns
null, the engine has declined (for example, the initials engine has no usable initials, or DiceBear was given an invalid style). The builder records the reason and moves to the next engine. - If it throws, the exception is recorded and the builder moves to the next engine — unless debug mode is enabled.
If the list is exhausted without a result, generate() throws
AllEnginesFailedException.
Building a chain
use Renfordt\AvatarSmithy\Avatar;
$avatar = Avatar::engine('gravatar') // primary
->fallbackTo('dicebear') // tried if gravatar declines/fails
->fallbackTo('initials') // final, local fallback
->seed('user@example.com')
->name('User Name')
->generate();
try() behaves the same as engine() for the first engine and as
fallbackTo() afterwards, which is convenient with Avatar::for():
$avatar = Avatar::for($user)
->try('gravatar')
->fallbackTo('initials')
->generate();
Choosing a final engine
Remote engines (Gravatar, DiceBear) depend on a network request and can decline
or fail. End the chain with a local engine that almost always succeeds. The
initials engine succeeds whenever the name yields at least one usable initial; if
the name is empty it declines, so a generative local engine such as pixel,
gradient, or bauhaus is a safe terminal choice when names may be missing.
Inspecting failures
After a partial or total failure you can read what happened:
$builder = Avatar::engine('gravatar')->fallbackTo('initials')->seed($email);
$avatar = $builder->generate();
foreach ($builder->getLastErrors() as $failure) {
// ['engine' => FQCN, 'error' => string, 'exception' => ?Throwable]
}
getLastErrors() is reset at the start of each generate() call.
Debug mode
With debugMode(true), the first failing engine stops the chain and its
exception is rethrown as EngineFailedException (wrapping the original). Use it
while developing to surface the underlying error instead of silently falling
through.
Avatar::engine('dicebear')
->debugMode()
->seed($email)
->generate(); // throws EngineFailedException on the first failure