--- name: polymorphic description: RSX polymorphic relationships with type references storing integers instead of class names. Use when implementing morphTo relationships, defining type_ref_columns, handling polymorphic form fields, or using polymorphic join helpers. --- # RSX Polymorphic Relationships ## Overview RSX uses a type reference system that stores **integers** in the database but transparently converts to/from class name strings in PHP. ```php $activity->eventable_type = 'Contact_Model'; // Stores integer in DB echo $activity->eventable_type; // Returns "Contact_Model" ``` **Benefits**: - Efficient integer storage (not VARCHAR class names) - Automatic type discovery - Transparent conversion - Laravel morphTo() compatibility --- ## Defining Type Reference Columns Declare which columns are type references in your model: ```php class Activity_Model extends Rsx_Model_Abstract { protected static $type_ref_columns = ['eventable_type']; public function eventable() { return $this->morphTo(); } } ``` The cast is automatically applied - no manual `$casts` needed. --- ## Database Schema Type reference columns must be **BIGINT**, not VARCHAR: ```sql CREATE TABLE activities ( id BIGINT NOT NULL AUTO_INCREMENT PRIMARY KEY, eventable_type BIGINT NULL, eventable_id BIGINT NULL, action VARCHAR(50) NOT NULL, INDEX idx_eventable (eventable_type, eventable_id) ); ``` --- ## Usage ### Setting Values ```php $activity = new Activity_Model(); $activity->eventable_type = 'Contact_Model'; // Use class name $activity->eventable_id = 123; $activity->save(); ``` ### Reading Values ```php echo $activity->eventable_type; // "Contact_Model" (string) $related = $activity->eventable; // Returns Contact_Model instance ``` ### Querying Class names are automatically converted to IDs in WHERE clauses: ```php // All work - class names auto-converted Activity_Model::where('eventable_type', 'Contact_Model')->get(); Activity_Model::whereIn('eventable_type', ['Contact_Model', 'Project_Model'])->get(); ``` --- ## Polymorphic Join Helpers Join tables with polymorphic columns: ```php // INNER JOIN - contacts that have attachments Contact_Model::query() ->joinMorph('file_attachments', 'fileable') ->select('contacts.*', 'file_attachments.filename') ->get(); // LEFT JOIN - all contacts, with attachments if they exist Contact_Model::query() ->leftJoinMorph('file_attachments', 'fileable') ->get(); // RIGHT JOIN Contact_Model::query() ->rightJoinMorph('file_attachments', 'fileable') ->get(); ``` **Parameters**: - `$table` - Table with polymorphic columns (e.g., 'file_attachments') - `$morphName` - Column prefix (e.g., 'fileable' for fileable_type/fileable_id) - `$morphClass` - Optional explicit class (defaults to current model) --- ## Form Handling ### Client-Side Format Polymorphic fields submit as JSON: ```javascript eventable={"model":"Contact_Model","id":123} ``` ### Server-Side Parsing ```php use App\RSpade\Core\Polymorphic_Field_Helper; #[Ajax_Endpoint] public static function save(Request $request, array $params = []) { $eventable = Polymorphic_Field_Helper::parse($params['eventable'], [ Contact_Model::class, Project_Model::class, ]); // Validate if ($error = $eventable->validate('Please select an entity')) { return response_error(Ajax::ERROR_VALIDATION, ['eventable' => $error]); } // Use $activity = new Activity_Model(); $activity->eventable_type = $eventable->model; // "Contact_Model" $activity->eventable_id = $eventable->id; // 123 $activity->save(); } ``` **Important**: Always use `Model::class` for the whitelist. --- ## Auto-Discovery When storing a new class name that isn't in `_type_refs` yet: ```php $attachment->fileable_type = 'Custom_Model'; $attachment->save(); ``` RSX will: 1. Verify `Custom_Model` exists and extends `Rsx_Model_Abstract` 2. Create a new `_type_refs` entry with next available ID 3. Store that ID in the column Any model can be used without pre-registration. --- ## Common Patterns ### File Attachments to Multiple Models ```php class File_Attachment_Model extends Rsx_Model_Abstract { protected static $type_ref_columns = ['fileable_type']; public function fileable() { return $this->morphTo(); } } // Attach to contact $attachment->fileable_type = 'Contact_Model'; $attachment->fileable_id = $contact->id; // Attach to project $attachment->fileable_type = 'Project_Model'; $attachment->fileable_id = $project->id; ``` ### Activity Log ```php class Activity_Model extends Rsx_Model_Abstract { protected static $type_ref_columns = ['subject_type']; public function subject() { return $this->morphTo(); } } // Log activity for any model Activity_Model::log('updated', $contact); // subject_type = 'Contact_Model' Activity_Model::log('created', $project); // subject_type = 'Project_Model' ``` --- ## Simple Names Only Always use simple class names (basename), never FQCNs: ```php // ✅ Correct $activity->eventable_type = 'Contact_Model'; // ❌ Wrong - fully qualified $activity->eventable_type = 'App\\Models\\Contact_Model'; ``` ## More Information Details: `php artisan rsx:man polymorphic`