Weave Code
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

Atrium Laravel Package

atriumphp/atrium

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps for New Features

  1. Relations & Nesting: Start by defining a relations() method in your AdminResource to declare one-to-many or many-to-many relationships. For example:

    public static function relations(): array
    {
        return [
            Relation::make('comments', CommentResource::class)
                ->oneToMany()
                ->foreignKey('article_id'),
        ];
    }
    
    • Use ->using(RelationManagerConfiguration::class) to extract relation logic into a dedicated class for complex setups.
  2. Nested Resources: Declare a parent relationship in your resource:

    public static function parent(): ?ParentRelation
    {
        return ParentRelation::make(ProjectResource::class)
            ->relationship('tasks')
            ->foreignKey('project_id')
            ->recordTitle('name');
    }
    
    • Nested routes (/{prefix}/{parentResource}/{parentId}/{resource}/...) are auto-generated.
  3. Record View Pages: Add a read-only view page to your resource:

    public static function view(Schema $schema): Schema
    {
        return $schema->columns([
            Entry::make('title', 'Title'),
            Entry::make('content', 'Content'),
        ]);
    }
    
  4. Custom Identifier Field: Override getIdentifierField() for non-standard keys (e.g., slugs):

    public static function getIdentifierField(): string
    {
        return 'slug';
    }
    

First Use Case

  • Quick Win: Add a one-to-many relation manager to an existing resource (e.g., Article → Comments). Use the auto-generated inline modal for CRUD operations.
  • Advanced: Nest a resource (e.g., Project → Tasks) and leverage parent-scoped filtering/URLs.

Implementation Patterns

Core Workflows

  1. Relation Managers:

    • One-to-Many: Auto-generates CRUD modals (create/edit/delete) + associate/dissociate pickers. Use Relation::readOnlyOnView(true) to disable editing on the view page.
    • Many-to-Many: Supports attach/detach actions with pivot columns. Tabs auto-activate for multiple relations.
    • Extracted Config: Move complex relation logic (e.g., custom table columns) to a RelationManagerConfiguration class for reusability.
  2. Nested Resources:

    • Parent-Child Scoping: All routes/queries are scoped to the parent record. Use parentResourceSlug in PageContext for nested URLs.
    • Breadcrumbs: Auto-generated ancestry (e.g., Projects › Alpha › Tasks). Override ParentRelation::recordTitle() for custom display names.
  3. View Pages:

    • Schema-Driven: Define read-only entries (e.g., Entry::make('title')) in a Schema. Falls back to form() fields if view() is omitted.
    • Layout: Entries inherit styling/behavior from form fields (e.g., labels, tooltips).
  4. Custom Identifiers:

    • URL Resolution: Override getIdentifierField() to use fields like slug or uuid. Ensure scopeQuery() handles custom lookups.

Integration Tips

  • Authorization: Use hooks like canAssociate(), canDetach(), or canAttach() to restrict relation actions.
  • Data Providers: Extend RelationDataProvider for custom pivot-table logic (e.g., Doctrine or array adapters).
  • Live Components: Host relation managers in RelationManagers or embed Atrium\Action\Form with relationResource/relationName for modal forms.
  • Migration: Replace path_prefix with parent() for nested routes. Use nestedUrl() in PageContext for dynamic URLs.

Gotchas and Tips

Pitfalls

  1. Breaking Changes:

    • Relation::form() Activation: Pre-0.2.0, inline form() closures were ignored. Now, they’re applied in modals. Update resources using Relation::form(...).
    • DataProviderInterface::find(): Signature changed to include $idField. Third-party providers must implement the new parameter.
    • ActionContext: No longer final; extend NestedActionContext for nested routes.
  2. Nested Resources:

    • Foreign Key Mismatch: The system validates parent() against the registry. Ensure foreignKey() matches the parent’s relation.
    • 404s: Child records with forged IDs (not linked to the parent) return 404s. Test edge cases with scopeQuery().
    • Route Collisions: Nested routes use a 5-segment pattern (/{prefix}/{parentResource}/{parentId}/{resource}/...). Avoid overlapping with flat routes.
  3. Relation Managers:

    • Many-to-Many Pivot Columns: Display in tables is a future enhancement. Use pivotColumns() for data but not UI yet.
    • Owned CRUD: Create/edit/delete actions gate on the target resource’s can(...) permissions, not the parent’s.
    • Visibility: Use Relation::visible(fn ($parent) => ...) to hide managers conditionally.
  4. Custom Identifiers:

    • Performance: Doctrine uses identity-map for primary keys but falls back to WHERE <field> = :id for custom fields. Avoid complex queries in scopeQuery().
    • URL Generation: Ensure getIdentifierField() returns a field that’s both readable and resolvable (e.g., slug must exist in the DB).

Debugging Tips

  1. Relation Errors:

    • Check relations() for valid oneToMany()/manyToMany() declarations and matching foreign keys.
    • Use php artisan atrium:debug:relations (if available) to inspect registered relations.
  2. Nested Routes:

    • Verify parent() returns a valid ParentRelation with a registered parent resource.
    • Test nested URLs with route('atrium.admin.resources.{resource}.index') and pass parentId.
  3. View Pages:

    • If view() is empty, the system falls back to form() fields. Explicitly return Schema::make() to avoid surprises.
    • Use dd($this->record) in ViewPage to inspect the resolved record.
  4. Authorization:

    • Override hooks like canAssociate() in your AdminResource. Log denials to debug:
      public static function canAssociate($parent, $child): bool
      {
          if (!someCondition($parent, $child)) {
              \Log::debug('Association denied', ['parent' => $parent, 'child' => $child]);
              return false;
          }
          return true;
      }
      

Extension Points

  1. Custom Relation Managers:

    • Extend RelationManagerConfiguration to override table columns, forms, or actions.
    • Example: Add a custom "archive" button to a relation manager:
      public function table(): Table
      {
          return parent::table()
              ->action('archive', 'Archive')
              ->url(fn ($record) => route('atrium.admin.relations.archive', [
                  'resource' => $this->resource,
                  'relation' => $this->relationName,
                  'id' => $record->id,
              ]));
      }
      
  2. Data Providers:

    • Implement RelationDataProvider for non-Doctrine setups (e.g., Eloquent with custom queries):
      class CustomRelationDataProvider implements RelationDataProvider
      {
          public function findManyByForeignKey(string $foreignKey, array $values): array
          {
              return YourModel::where($foreignKey, $values)->get();
          }
      }
      
  3. Nested Actions:

    • Extend NestedActionContext to add custom logic to nested routes (e.g., middleware):
      class CustomNestedContext extends NestedActionContext
      {
          public function getMiddleware(): array
          {
              return array_merge(parent::getMiddleware(), [
                  \App\Http\Middleware\CheckProjectAccess::class,
              ]);
          }
      }
      
  4. View Entries:

    • Create custom Entry classes (e.g., MarkdownEntry) by extending Atrium\View\Entry:
      class MarkdownEntry extends Entry
      {
          public function render(): string
          {
              return marked($this->value);
          }
      }
      
      Use in view():
      Entry::make('description', 'Description')->type(MarkdownEntry::class)
      
  5. Icon Migration:

    • Replace panel icons with Symfony UX Icons. Update your resource classes:
      public static function icon(): string
      {
          return 'heroicon-o-collection'; // Symfony UX Icon name
      }
      
      Check the Symfony UX Icons documentation for available icons.
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.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views