Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Eg R2 Laravel Package

litalico-engineering/eg-r2

A Laravel package from LITALICO Engineering that integrates Cloudflare R2 storage as an S3-compatible filesystem disk, letting you upload and serve files through Laravel's Storage API with simple configuration.

View on GitHub
Deep Wiki
Context7

Getting Started

eg-r2 is installed like any Laravel package:

composer require litalico-engineering/eg-r2

There is no separate service-provider registration step on Laravel 9+ — package discovery handles it. If the package ships a config file, publish it once and commit it:

php artisan vendor:publish --tag=eg-r2-config

Where to look first, in this order:

  1. The Property attribute class (src/Attributes/Property.php or similar). This is the contract everything else is built on — its constructor arguments tell you what metadata the package actually consumes.
  2. The reflection/discovery class that scans your models or DTOs. Read it before you write attributes; it is the source of truth for which targets (class, property, method) and which discovery paths are supported.
  3. The config file, for the list of namespaces/paths that get scanned.

First use case: pick one small Eloquent model or DTO, annotate two or three properties with the package's attributes, and dump the resulting output from php artisan tinker:

(new ReflectionClass(Post::class))->getAttributes(Property::class, ReflectionAttribute::IS_INSTANCEOF);

Confirming the reflection picks up your attributes before wiring anything into controllers saves a lot of confusion later. Then run the package's generation/consumption entry point (an artisan command or a facade call, depending on the version) against that single model and compare the output to what you declared.

Implementation Patterns

Annotate declaratively, not imperatively. The whole point of the package is that property metadata lives next to the property it describes. Resist the urge to build a config array that mirrors your model — you lose the co-location benefit and the two definitions drift.

Subclass Property for domain-specific attributes. This is the pattern that 1.5.3 explicitly unblocked. Instead of repeating the same argument list on every property:

#[Attribute(Attribute::TARGET_PROPERTY)]
class Email extends Property
{
    public function __construct()
    {
        parent::__construct(type: 'string', format: 'email');
    }
}

class User extends Model
{
    #[Email]
    public string $address;
}

Keep a small App\Support\Attributes (or App\Attributes) namespace for these and treat it as part of your public model contract. This scales far better than scattering raw #[Property(...)] with eight positional arguments across a hundred fields.

Start with one bounded context. Introduce the package on a single module or resource, generate, diff the output against the hand-written equivalent, and only then roll it out. The failure mode of schema/metadata generators is "big bang migration, three hundred diffs, nobody reviews them."

Integrate at the boundary, not in the domain. Wrap the package's generation call behind a thin application service (or an artisan command) so controllers, jobs, and tests call your method. When the package's API shifts — or when you need to swap it out — you change one file.

Snapshot the output in tests. Whatever the package emits, assert on it with a snapshot/golden-file test over a fixture model that exercises each attribute type, including your subclasses. This is what catches a regression the next time the reflection layer changes.

Cache the generated artefact, not the reflection. Reflection is per-request overhead; generation is usually cheap enough to run in CI or a deploy step. Produce the output at build/deploy time and ship the result rather than recomputing on every request.

Gotchas and Tips

1.5.3 is the release that makes subclasses work — pin it. Before this fix, an attribute class inheriting from Property was not recognized during reflection: you'd declare #[Email] on a property and get silence, no exception, no warning. If you have subclasses sitting in your codebase that "don't do anything," this is why. Bump to ^1.5.3 and re-run your snapshot test.

ReflectionAttribute::IS_INSTANCEOF is the mechanism. If you write your own reflection loops around this package's attributes, you must pass the flag — getAttributes(Property::class) without it matches only exact class names and will miss every subclass:

// misses subclasses
$attrs = $ref->getAttributes(Property::class);

// matches Property and anything extending it
$attrs = $ref->getAttributes(Property::class, ReflectionAttribute::IS_INSTANCEOF);

Don't forget #[Attribute] on the subclass itself. PHP's attribute flag is not inherited from the parent class. A subclass of Property without its own #[Attribute(Attribute::TARGET_PROPERTY)] will fail at the point of use, with an error that points at the usage site rather than the class definition — easy to misread as a package bug.

Target flags matter. TARGET_PROPERTY vs TARGET_CLASS vs TARGET_METHOD is enforced by PHP, not by the package. If the package reads property-level attributes and you declare yours at class level "for convenience," nothing will be picked up.

Silent no-ops are the dominant failure mode. Nothing in this pipeline throws when an attribute is unsupported, mis-targeted, or on a class outside the configured discovery paths. When output is missing, check in this order: (1) is the class in a scanned namespace, (2) does the attribute have the right target flag, (3) does the attribute class carry #[Attribute], (4) are you passing IS_INSTANCEOF in any custom reflection.

Clear config and classmap caches when changing discovery config. php artisan config:clear and composer dump-autoload after moving classes between namespaces — cached config in particular will silently keep the old scan paths in local development.

Repeatable attributes need explicit ordering discipline. If you allow more than one Property (or subclass) on the same property, define precedence yourself in the consuming code rather than relying on declaration order — the order getAttributes() returns is declaration order today, but basing business logic on it is brittle.

Extension points to prefer: subclassing Property (now safe), the package's config for scan paths, and whatever hook exists for post-processing the generated output. Avoid subclassing the reflection/discovery service itself — that's the layer most likely to be refactored between minor versions, and the 1.5.3 fix is a reminder that its behaviour is still being tuned.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo