aurorawebsoftware / flexyfield
Laravel Models are now Uber Flexy!
Fund package maintenance!
AuroraWebSoftware
Installs: 1 292
Dependents: 1
Suggesters: 0
Security: 0
Stars: 23
Watchers: 1
Forks: 2
Open Issues: 0
pkg:composer/aurorawebsoftware/flexyfield
Requires
- php: ^8.2|^8.3|^8.4
- illuminate/contracts: ^11.0||^12.0
- spatie/laravel-package-tools: ^1.16
Requires (Dev)
- larastan/larastan: ^3
- laravel/pint: ^1.14
- nunomaduro/collision: ^8
- orchestra/testbench: ^10.0||^9.0.0
- pestphp/pest: ^3
- pestphp/pest-plugin-arch: ^3
- pestphp/pest-plugin-laravel: ^3
- phpstan/extension-installer: ^1
- phpstan/phpstan-deprecation-rules: ^2
- phpstan/phpstan-phpunit: ^2
This package is auto-updated.
Last update: 2025-12-08 15:18:19 UTC
README
Because your models deserve superpowers π¦Έ
Ever wished you could add fields to your Laravel models without touching migrations?
Now you can. Welcome to FlexyField.
composer require aurorawebsoftware/flexyfield php artisan migrate
The Magic β¨
// Give your model the power class Product extends Model implements FlexyModelContract { use Flexy; } // Create a schema (think of it as a "field template") Product::createSchema('electronics', 'Electronics'); Product::addFieldToSchema('electronics', 'voltage', FlexyFieldType::STRING); Product::addFieldToSchema('electronics', 'warranty_years', FlexyFieldType::INTEGER); // Use it like it was always there $tv = Product::create(['name' => 'Smart TV']); $tv->assignToSchema('electronics'); $tv->flexy->voltage = '220V'; $tv->flexy->warranty_years = 2; $tv->save(); // Query like a boss Product::where('flexy_voltage', '220V')->get();
No migrations. No schema changes. Just vibes. π
Why FlexyField?
| Problem | Old Way | FlexyField Way |
|---|---|---|
| "We need a new product attribute" | Migration + deploy + pray π | addFieldToSchema() β
|
| "Different products need different fields" | JSON column chaos π± | Schemas! π― |
| "Can we query by that custom field?" | nervous laughter | where('flexy_field', $value) π |
Field Types
| Type | What it stores | Example |
|---|---|---|
STRING |
Text | $m->flexy->color = 'blue' |
INTEGER |
Whole numbers | $m->flexy->stock = 42 |
DECIMAL |
Money, measurements | $m->flexy->price = 99.99 |
BOOLEAN |
Yes/No | $m->flexy->active = true |
DATE |
Dates | $m->flexy->release = '2024-01-01' |
DATETIME |
Timestamps | $m->flexy->created = now() |
JSON |
Arrays, objects | $m->flexy->tags = ['hot', 'new'] |
FILE |
Uploads | $m->flexy->manual = $request->file('pdf') |
Real-World Examples π
E-Commerce (PIM Style)
// Shoes have sizes and colors Product::createSchema('footwear', 'Footwear'); Product::addFieldToSchema('footwear', 'shoe_size', FlexyFieldType::INTEGER, validationRules: 'required|between:35,50'); Product::addFieldToSchema('footwear', 'color', FlexyFieldType::STRING, fieldMetadata: ['options' => ['black', 'white', 'red', 'blue']]); // Books have ISBNs and authors Product::createSchema('books', 'Books'); Product::addFieldToSchema('books', 'isbn', FlexyFieldType::STRING, validationRules: 'required|size:13'); Product::addFieldToSchema('books', 'author', FlexyFieldType::STRING); Product::addFieldToSchema('books', 'pages', FlexyFieldType::INTEGER); // Same model, different fields! $sneakers = Product::create(['name' => 'Air Max']); $sneakers->assignToSchema('footwear'); $sneakers->flexy->shoe_size = 42; $sneakers->flexy->color = 'black'; $novel = Product::create(['name' => 'Clean Code']); $novel->assignToSchema('books'); $novel->flexy->isbn = '9780132350884'; $novel->flexy->author = 'Robert C. Martin';
CRM (Customer Segments)
// B2B customers need company info Contact::createSchema('b2b', 'Business Customers'); Contact::addFieldToSchema('b2b', 'company_name', FlexyFieldType::STRING); Contact::addFieldToSchema('b2b', 'employee_count', FlexyFieldType::INTEGER); Contact::addFieldToSchema('b2b', 'annual_revenue', FlexyFieldType::DECIMAL); // B2C customers need personal preferences Contact::createSchema('b2c', 'Individual Customers'); Contact::addFieldToSchema('b2c', 'birthday', FlexyFieldType::DATE); Contact::addFieldToSchema('b2c', 'interests', FlexyFieldType::JSON, fieldMetadata: ['options' => ['tech', 'sports', 'music', 'travel'], 'multiple' => true]); // Query by segment $bigCompanies = Contact::whereSchema('b2b') ->where('flexy_annual_revenue', '>', 1000000) ->get();
Multi-tenant SaaS
// Each tenant can have custom fields! $tenantSchema = "tenant_{$tenant->id}_leads"; Lead::createSchema($tenantSchema, "{$tenant->name} Leads"); Lead::addFieldToSchema($tenantSchema, 'source', FlexyFieldType::STRING); Lead::addFieldToSchema($tenantSchema, 'score', FlexyFieldType::INTEGER); // Tenant-specific fields added via admin panel foreach ($tenant->customFields as $field) { Lead::addFieldToSchema($tenantSchema, $field->name, $field->type); }
Cool Features π
Dropdowns & Multi-select
// Single choice Product::addFieldToSchema('schema', 'size', FlexyFieldType::STRING, fieldMetadata: ['options' => ['S', 'M', 'L', 'XL']]); // Multiple choices (use JSON type!) Product::addFieldToSchema('schema', 'features', FlexyFieldType::JSON, fieldMetadata: ['options' => ['wifi', 'bluetooth', '5g'], 'multiple' => true]); $phone->flexy->size = 'M'; $phone->flexy->features = ['wifi', '5g']; // Array!
File Uploads (with Security Baked In π)
Product::addFieldToSchema('schema', 'manual', FlexyFieldType::FILE, validationRules: 'required|mimes:pdf|max:5120', fieldMetadata: ['disk' => 's3', 'allowed_extensions' => ['pdf']]); $product->flexy->manual = $request->file('manual'); $product->save(); // Get URLs $url = $product->getFlexyFileUrl('manual'); $signedUrl = $product->getFlexyFileUrlSigned('manual', now()->addHour()->timestamp);
Validation (Because Data Integrity Matters)
Product::addFieldToSchema('schema', 'email', FlexyFieldType::STRING, validationRules: 'required|email|max:255', validationMessages: ['email.email' => 'GeΓ§erli bir email girin!']); $product->flexy->email = 'not-an-email'; $product->save(); // π₯ ValidationException!
UI Hints & Grouping
Product::addFieldToSchema('schema', 'battery', FlexyFieldType::INTEGER, label: 'Battery Capacity', fieldMetadata: [ 'group' => 'Technical Specs', 'placeholder' => 'mAh', 'hint' => 'Typical range: 3000-5000' ]); // Perfect for building dynamic forms! $schema->getFieldsGrouped(); // ['Technical Specs' => [...], 'Ungrouped' => [...]]
Querying π
// Simple Product::where('flexy_color', 'blue')->get(); // Dynamic method (Laravel magic!) Product::whereFlexyColor('blue')->get(); // By schema Product::whereSchema('electronics')->get(); Product::whereSchemaIn(['electronics', 'furniture'])->get(); // Go wild Product::whereSchema('electronics') ->where('flexy_price', '<', 100) ->where('flexy_active', true) ->orderBy('flexy_price') ->get();
Configuration βοΈ
Publish the config file:
php artisan vendor:publish --tag="flexyfield-config"
// config/flexyfield.php return [ 'file_storage' => [ 'default_disk' => env('FLEXYFIELD_DEFAULT_DISK', 'public'), 'default_path' => env('FLEXYFIELD_DEFAULT_PATH', 'flexyfield'), 'path_structure' => '{model_type}/{schema_code}/{field_name}/{year}/{month}', 'cleanup_on_delete' => true, // Auto-delete files when model deleted 'enable_security_logging' => true, // Log security events ], ];
Environment Variables:
FLEXYFIELD_DEFAULT_DISK=s3 FLEXYFIELD_DEFAULT_PATH=uploads/flexy FLEXYFIELD_CLEANUP_DELETE=true FLEXYFIELD_SECURITY_LOGGING=true
AI-Powered Development π€
FlexyField comes with Laravel Boost guidelines for AI agents!
resources/boost/guidelines/core.blade.php
Your AI assistant (Claude, GPT, Copilot) can read this file and instantly understand:
- All API methods and signatures
- Field types and metadata options
- Common patterns and best practices
- Error handling and exceptions
Just point your AI to the guideline file and watch it write perfect FlexyField code! π―
Don't Do This β
// Setting values before assigning schema $product->flexy->field = 'x'; // π₯ Exception! // Always assign first! $product->assignToSchema('electronics'); $product->flexy->field = 'x'; // β // Wrong query syntax Product::where('flexy->field', 'x'); // π« Nope // Use underscore prefix Product::where('flexy_field', 'x'); // β Yes!
Performance π
- Smart view recreation - Only rebuilds when NEW fields are added
- Scales well - Tested with 50+ fields, 1M+ records
- Manual rebuild -
php artisan flexyfield:rebuild-view
Requirements
- PHP 8.2+
- Laravel 11+
- MySQL 8+ or PostgreSQL 16+
Documentation
| Guide | What's Inside |
|---|---|
| Performance | Make it fly π |
| Best Practices | Do it right β |
| Deployment | Ship it safely π¦ |
| Troubleshooting | Fix it fast π§ |
| File Security | Lock it down π |
Contributing
composer install ./vendor/bin/pest # Run tests ./vendor/bin/phpstan analyse # Static analysis ./vendor/bin/pint # Code style
PRs welcome! π€
License
MIT - Go build something awesome! π
Made with β by Aurora Web Software
β Star us on GitHub!