model_class = $model_class; $this->attempted_fields = $attempted_fields; $this->method_name = $method_name ?: ($was_force ? 'forceFill' : 'fill'); $message = $this->build_message($is_static); parent::__construct($message); } /** * Build the exception message with helpful guidance * * @param bool $is_static * @return string */ protected function build_message($is_static) { $short_class = class_basename($this->model_class); $var_name = '$' . strtolower(preg_replace('/(?attempted_fields); $message = "🚫 MASS ASSIGNMENT PROHIBITED IN RSPADE FRAMEWORK\n\n"; $message .= "Model: {$this->model_class}\n"; $message .= "Method: {$this->method_name}()\n"; if (!empty($this->attempted_fields)) { $message .= "Attempted fields: {$fields_list}\n"; } $message .= "\n"; $message .= "The RSpade framework prohibits mass assignment for security and code clarity.\n"; $message .= "All model fields must be explicitly assigned one by one.\n\n"; $message .= "āŒ INCORRECT (mass assignment):\n"; if ($is_static) { if ($this->method_name === 'create') { $message .= "{$short_class}::create(\$request->all());\n"; $message .= "{$short_class}::create(\$request->validated());\n"; } elseif ($this->method_name === 'firstOrCreate') { $message .= "{$short_class}::firstOrCreate(['email' => \$email], \$data);\n"; } elseif ($this->method_name === 'updateOrCreate') { $message .= "{$short_class}::updateOrCreate(['id' => \$id], \$data);\n"; } } else { if ($this->method_name === 'update') { $message .= "{$var_name}->update(\$request->all());\n"; $message .= "{$var_name}->update(\$request->validated());\n"; } else { $message .= "{$var_name}->fill(\$request->all());\n"; $message .= "{$var_name}->forceFill(\$data);\n"; } } $message .= "\nāœ… CORRECT (explicit field assignment):\n"; // Generate example based on attempted fields if (!empty($this->attempted_fields)) { if ($is_static || $this->method_name === 'update') { if ($this->method_name === 'update') { $message .= "{$var_name} = {$short_class}::find(\$id);\n"; } else { $message .= "{$var_name} = new {$short_class}();\n"; } foreach ($this->attempted_fields as $field) { $message .= "{$var_name}->{$field} = \$request->input('{$field}');\n"; } $message .= "{$var_name}->save();\n"; } } else { // Generic example $message .= "{$var_name} = new {$short_class}();\n"; $message .= "{$var_name}->name = \$request->input('name');\n"; $message .= "{$var_name}->email = \$request->input('email');\n"; $message .= "{$var_name}->status = \$request->input('status');\n"; $message .= "{$var_name}->save();\n"; } $message .= "\n"; $message .= "For finding and updating:\n"; $message .= "{$var_name} = {$short_class}::where('email', \$email)->first();\n"; $message .= "if (!{$var_name}) {\n"; $message .= " {$var_name} = new {$short_class}();\n"; $message .= " {$var_name}->email = \$email;\n"; $message .= "}\n"; $message .= "{$var_name}->name = \$request->input('name');\n"; $message .= "{$var_name}->save();\n"; $message .= "\n"; $message .= "Benefits of explicit assignment:\n"; $message .= "• Clear visibility of what fields are being set\n"; $message .= "• Protection against unexpected field injection\n"; $message .= "• Easier to debug and maintain\n"; $message .= "• Type safety with IDE autocompletion\n"; $message .= "• No need for \$fillable or \$guarded arrays\n"; $message .= "\n"; $message .= "Note: The \$fillable property is not needed in RSpade models.\n"; $message .= "Remove any \$fillable or \$guarded properties from your models.\n"; return $message; } /** * Get the model class that triggered the exception * * @return string */ public function get_model_class() { return $this->model_class; } /** * Get the fields that were attempted to be mass assigned * * @return array */ public function get_attempted_fields() { return $this->attempted_fields; } }