| name | developing-shopper |
| description | Provides coding standards and patterns for Shopper development. Use when creating or modifying Models, Actions, Enums, Livewire components, migrations, or tests in any Shopper package. |
Developing Shopper
Monorepo Structure
| Package | Namespace | Purpose |
|---|
packages/admin | Shopper\ | Livewire components, views, routes |
packages/core | Shopper\Core\ | Models, Actions, Enums, Contracts |
packages/sidebar | Shopper\Sidebar\ | Sidebar navigation |
packages/shipping | Shopper\Shipping\ | Shipping providers |
Required in Every PHP File
<?php
declare(strict_types=1);
Class Element Order
- Traits → 2. Cases → 3. Constants → 4. Properties → 5. Constructor → 6. Magic methods → 7. Methods (public → protected → private)
Models
See MODELS.md for the swappable model pattern.
class Product extends Model implements ProductContract
{
use HasFactory;
use HasModelContract;
use HasSlug;
protected $guarded = [];
public static function configKey(): string
{
return 'product';
}
public function getTable(): string
{
return shopper_table('products');
}
protected function casts(): array
{
return ['featured' => 'boolean'];
}
}
Actions
final class CreateOrderAction
{
public function execute(array $data): Order
{
}
}
Enums
enum OrderStatus: string implements HasColor, HasIcon, HasLabel
{
use ArrayableEnum;
use HasEnumStaticMethods;
case Pending = 'pending';
public function getLabel(): string
{
return __('shopper-core::enum/order.pending');
}
}
Livewire Components
class ProductForm extends Component implements HasActions, HasForms
{
use InteractsWithActions;
use InteractsWithForms;
public ?array $data = [];
#[Computed]
public function categories(): Collection
{
return resolve(CategoryContract::class)::query()->get();
}
public function render(): View
{
return view('shopper::livewire.product-form');
}
}
Migrations
return new class extends \Shopper\Core\Helpers\Migration
{
public function up(): void
{
Schema::create($this->getTableName('products'), function (Blueprint $table): void {
$this->addCommonFields($table, hasSoftDelete: true);
$this->addSeoFields($table);
$this->addShippingFields($table);
$this->addForeignKey($table, 'brand_id', $this->getTableName('brands'));
});
}
};
Testing
beforeEach(function (): void {
$this->user = User::factory()->create();
});
it('creates a product', function (): void {
$this->actingAs($this->user);
Livewire::test(ProductForm::class)
->set('data.name', 'Test')
->call('save')
->assertHasNoErrors();
})->group('products');
Commands
composer test:sqlite
composer test:types
composer cs