<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Abdullah Sowailem</title>
    <description>The latest articles on Forem by Abdullah Sowailem (@sowailem).</description>
    <link>https://forem.com/sowailem</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3430315%2F142f0e59-1683-45c7-ac2e-3e9ff4f00878.jpg</url>
      <title>Forem: Abdullah Sowailem</title>
      <link>https://forem.com/sowailem</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/sowailem"/>
    <language>en</language>
    <item>
      <title>FieldGuard Dynamic Field-Level Security for Laravel</title>
      <dc:creator>Abdullah Sowailem</dc:creator>
      <pubDate>Mon, 02 Feb 2026 13:13:28 +0000</pubDate>
      <link>https://forem.com/sowailem/fieldguard-dynamic-field-level-security-for-laravel-4268</link>
      <guid>https://forem.com/sowailem/fieldguard-dynamic-field-level-security-for-laravel-4268</guid>
      <description>&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lutpn8gufrxdb0r65oz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F1lutpn8gufrxdb0r65oz.png" alt="FieldGuard" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;FieldGuard is a lightweight, non-intrusive Laravel package for field-level security on Eloquent models. It allows you to control which users can view or modify specific attributes using dynamic, database-driven rules.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.youtube.com/watch?v=vbixycjWKHo" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9ob7n64wdkyob3x68qpr.png" alt="YouTube Video" width="800" height="446"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Database-Driven Rules&lt;/strong&gt;: Create and manage security rules in the database for runtime configuration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Non-Intrusive&lt;/strong&gt;: No traits, base classes, or attributes required for your models.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Automatic Enforcement&lt;/strong&gt;: Optionally enforce security via model events (&lt;code&gt;retrieved&lt;/code&gt;, &lt;code&gt;saving&lt;/code&gt;) without any code changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Read &amp;amp; Write Protection&lt;/strong&gt;: Separate rules for viewing and updating fields.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data Masking&lt;/strong&gt;: Automatically mask sensitive fields (e.g., &lt;code&gt;***-***-***&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Middleware Integration&lt;/strong&gt;: Automatically filter unauthorized fields from incoming requests.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Caching&lt;/strong&gt;: Performance-optimized with Laravel cache support for database rules.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No-Code Friendly&lt;/strong&gt;: Centralized control without altering your core models.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Installation
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require sowailem/fieldguard
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the migrations to create the rules table:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan migrate
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Usage
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Creating Security Rules
&lt;/h3&gt;

&lt;p&gt;All field-level permissions are managed through the &lt;code&gt;field_guard_rules&lt;/code&gt; table. You can use the &lt;code&gt;FieldGuardRule&lt;/code&gt; model to create rules.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Sowailem\FieldGuard\Models\FieldGuardRule&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;FieldGuardRule&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
    &lt;span class="s1"&gt;'model_class'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'App\Models\User'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'field_name'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'salary'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'read_policy'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'roles'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'hr'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="s1"&gt;'allow_self'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="s1"&gt;'write_policy'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'roles'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'admin'&lt;/span&gt;&lt;span class="p"&gt;]],&lt;/span&gt;
    &lt;span class="s1"&gt;'mask'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'PROTECTED'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'is_active'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Rule Structure
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;model_class&lt;/code&gt;: Fully qualified class name of the Eloquent model.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;field_name&lt;/code&gt;: The name of the attribute to secure.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;read_policy&lt;/code&gt;: (Optional) Permission for viewing the field. Can be a string or JSON object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;write_policy&lt;/code&gt;: (Optional) Permission for creating or updating the field. Can be a string or JSON object.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;mask&lt;/code&gt;: (Optional) Value to return if &lt;code&gt;read&lt;/code&gt; permission is denied (instead of removing the field).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;is_active&lt;/code&gt;: Boolean to enable/disable the rule (defaults to true).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Policy Types
&lt;/h4&gt;

&lt;p&gt;Policies can be:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Gate Name&lt;/code&gt;: A Laravel Gate name (e.g., &lt;code&gt;'view-salary'&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'self'&lt;/code&gt;: Allows access if the user's ID matches the model's primary key.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'role:name'&lt;/code&gt;: Requires the user to have a specific role (expects a &lt;code&gt;hasRole($role)&lt;/code&gt; method on the User model).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;'true'&lt;/code&gt; / &lt;code&gt;'false'&lt;/code&gt;: Always allow or always deny.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;JSON Array&lt;/code&gt;: For complex logic (e.g., &lt;code&gt;['roles' =&amp;gt; ['admin'], 'allow_self' =&amp;gt; true, 'gate' =&amp;gt; 'extra-check']&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  2. Enforcing Security
&lt;/h3&gt;

&lt;h4&gt;
  
  
  Automatic Enforcement (Global)
&lt;/h4&gt;

&lt;p&gt;You can enable automatic enforcement for all models by setting &lt;code&gt;automatic_enforcement&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; in your &lt;code&gt;config/fieldguard.php&lt;/code&gt;. This uses Eloquent events to filter fields automatically.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'automatic_enforcement'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Read&lt;/strong&gt;: Automatically hides or masks fields when a model is retrieved from the database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Write&lt;/strong&gt;: Automatically prevents unauthorized fields from being saved (reverts to original values).&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Manual Enforcement (Read)
&lt;/h4&gt;

&lt;p&gt;Use the &lt;code&gt;FieldGuard&lt;/code&gt; facade to filter model attributes. This is useful in controllers or API resources.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Sowailem\FieldGuard\Facades\FieldGuard&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;view&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;User&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Returns the model attributes as an array, filtered by security rules&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;FieldGuard&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;auth&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  API Resource Integration
&lt;/h4&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;toArray&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;FieldGuard&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;apply&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;resource&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$request&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;user&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Automatic Enforcement (Middleware - Write)
&lt;/h4&gt;

&lt;p&gt;Register the middleware in your &lt;code&gt;bootstrap/app.php&lt;/code&gt; (Laravel 11+) or &lt;code&gt;app/Http/Kernel.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Laravel 11+ example in bootstrap/app.php&lt;/span&gt;
&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;withMiddleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;Middleware&lt;/span&gt; &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nv"&gt;$middleware&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;alias&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
        &lt;span class="s1"&gt;'fieldguard'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\Sowailem\FieldGuard\Middleware\EnforceFieldSecurityMiddleware&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Apply it to routes to filter request data before it reaches your controller:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nc"&gt;Route&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/users/{user}'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nc"&gt;UserController&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'update'&lt;/span&gt;&lt;span class="p"&gt;])&lt;/span&gt;
    &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;middleware&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'fieldguard:App\Models\User'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The middleware will automatically remove unauthorized fields from &lt;code&gt;$request-&amp;gt;all()&lt;/code&gt; before they reach your controller logic.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Caching
&lt;/h3&gt;

&lt;p&gt;Database rules are cached for performance. By default, they are cached using the tag &lt;code&gt;fieldguard:rules&lt;/code&gt; (configurable in &lt;code&gt;config/fieldguard.php&lt;/code&gt;). When you update rules via the provided &lt;code&gt;FieldGuardRuleRepository&lt;/code&gt;, the cache is automatically cleared.&lt;/p&gt;

&lt;p&gt;You can also manually clear the cache:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan fieldguard:clear-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  4. Custom Policy Resolvers
&lt;/h3&gt;

&lt;p&gt;If you need custom logic for interpreting database policies (e.g., integrating with a specific RBAC system), implement the &lt;code&gt;PolicyResolver&lt;/code&gt; interface and register it in &lt;code&gt;config/fieldguard.php&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Security&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Sowailem\FieldGuard\Contracts\PolicyResolver&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Database\Eloquent\Model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MyCustomResolver&lt;/span&gt; &lt;span class="kd"&gt;implements&lt;/span&gt; &lt;span class="nc"&gt;PolicyResolver&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;resolve&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;array&lt;/span&gt; &lt;span class="nv"&gt;$policy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;Model&lt;/span&gt; &lt;span class="nv"&gt;$model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;bool&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Your custom logic here&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register it in &lt;code&gt;config/fieldguard.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'resolver'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nc"&gt;\App\Security\MyCustomResolver&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  5. Seeding Initial Rules
&lt;/h3&gt;

&lt;p&gt;The package includes a seeder example to help you bootstrap rules. You can publish and run the seeder or use the provided example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan db:seed &lt;span class="nt"&gt;--class&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"Sowailem&lt;/span&gt;&lt;span class="se"&gt;\F&lt;/span&gt;&lt;span class="s2"&gt;ieldGuard&lt;/span&gt;&lt;span class="se"&gt;\D&lt;/span&gt;&lt;span class="s2"&gt;atabase&lt;/span&gt;&lt;span class="se"&gt;\S&lt;/span&gt;&lt;span class="s2"&gt;eeders&lt;/span&gt;&lt;span class="se"&gt;\F&lt;/span&gt;&lt;span class="s2"&gt;ieldGuardRuleSeeder"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  6. Administrative API
&lt;/h3&gt;

&lt;p&gt;FieldGuard comes with built-in RESTful API endpoints for managing security rules.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;GET /field-guard/rules&lt;/code&gt; – List all rules (supports pagination and filtering)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POST /field-guard/rules&lt;/code&gt; – Create a new rule&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;GET /field-guard/rules/{id}&lt;/code&gt; – View a specific rule&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PUT/PATCH /field-guard/rules/{id}&lt;/code&gt; – Update an existing rule&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DELETE /field-guard/rules/{id}&lt;/code&gt; – Delete a rule&lt;/li&gt;
&lt;/ul&gt;

&lt;h4&gt;
  
  
  Configuration
&lt;/h4&gt;

&lt;p&gt;You can customize the API prefix and middleware in &lt;code&gt;config/fieldguard.php&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="s1"&gt;'api'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'enabled'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'prefix'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'field-guard'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'middleware'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'api'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'auth:sanctum'&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Authorization
&lt;/h4&gt;

&lt;p&gt;The API uses a gate named &lt;code&gt;manage-field-guard&lt;/code&gt; to authorize requests. Ensure you define this gate in your &lt;code&gt;AuthServiceProvider&lt;/code&gt; or &lt;code&gt;AppServiceProvider&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\Gate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nc"&gt;Gate&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;define&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'manage-field-guard'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;isAdmin&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// Your authorization logic&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Publishing Routes
&lt;/h4&gt;

&lt;p&gt;If you want to customize the routes, you can publish them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;php artisan vendor:publish &lt;span class="nt"&gt;--tag&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"fieldguard-routes"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then disable the automatic loading in &lt;code&gt;config/fieldguard.php&lt;/code&gt; and manually register them in your &lt;code&gt;routes/api.php&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Testing
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;vendor/bin/phpunit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  License
&lt;/h2&gt;

&lt;p&gt;The MIT License (MIT). Please see &lt;a href="https://dev.toLICENSE"&gt;License File&lt;/a&gt; for more information.&lt;/p&gt;

</description>
      <category>laravel</category>
    </item>
    <item>
      <title>Laravel Ownable — A Smart Solution for Polymorphic Ownership</title>
      <dc:creator>Abdullah Sowailem</dc:creator>
      <pubDate>Tue, 12 Aug 2025 17:36:52 +0000</pubDate>
      <link>https://forem.com/sowailem/laravel-ownable-a-smart-solution-for-polymorphic-ownership-5a0g</link>
      <guid>https://forem.com/sowailem/laravel-ownable-a-smart-solution-for-polymorphic-ownership-5a0g</guid>
      <description>&lt;p&gt;`&lt;br&gt;
      &lt;/p&gt;
&lt;h2&gt;Introduction: Why Ownership Management Matters&lt;/h2&gt;
&lt;br&gt;
      &lt;p&gt;Ownership logic—where one model "owns" another—is ubiquitous in web apps: task assignments, document custody, product sellers, and delegated resources. While Laravel makes modeling relationships easy, it doesn't provide a simple, reusable pattern for robust ownership management, ownership transfer, and history tracking.&lt;/p&gt;
&lt;br&gt;
      &lt;p&gt;&lt;strong&gt;Laravel Ownable&lt;/strong&gt; fills that gap by offering a minimal, consistent API that lets &lt;em&gt;any&lt;/em&gt; Eloquent model act as an owner or be owned (polymorphic), while providing convenient methods and a facade for everyday ownership operations.&lt;/p&gt;
&lt;br&gt;
      &lt;h2&gt;What Is Laravel Ownable?&lt;/h2&gt;
&lt;br&gt;
      &lt;p&gt;&lt;strong&gt;Laravel Ownable&lt;/strong&gt; is a lightweight package that enables polymorphic ownership between Eloquent models. You get:&lt;/p&gt;
&lt;br&gt;
      &lt;ul&gt;

        &lt;li&gt;Polymorphic ownership — any model can own any other model.&lt;/li&gt;

        &lt;li&gt;Fluid, expressive methods for assigning, checking, and transferring ownership.&lt;/li&gt;

        &lt;li&gt;An easy-to-use facade for centralized actions.&lt;/li&gt;

        &lt;li&gt;A foundation you can extend for auditing, events, and bulk operations.&lt;/li&gt;

      &lt;/ul&gt;
&lt;br&gt;
      &lt;p&gt;Project docs: &lt;a href="https://sowailem.github.io/Ownable/" rel="noopener noreferrer"&gt;sowailem.github.io/Ownable&lt;/a&gt;&lt;/p&gt;
&lt;br&gt;
      &lt;h2&gt;Key Features&lt;/h2&gt;
&lt;br&gt;
      &lt;ul&gt;

        &lt;li&gt;
&lt;strong&gt;Polymorphism:&lt;/strong&gt; Model A can own Model B, or Model C — no rigid owner types.&lt;/li&gt;

        &lt;li&gt;
&lt;strong&gt;Convenience API:&lt;/strong&gt; Methods like &lt;code&gt;giveOwnershipTo&lt;/code&gt;, &lt;code&gt;ownedBy&lt;/code&gt;, &lt;code&gt;owns&lt;/code&gt;, etc.&lt;/li&gt;

        &lt;li&gt;
&lt;strong&gt;Facade:&lt;/strong&gt; Use a central &lt;code&gt;Owner&lt;/code&gt; facade for consistent calls.&lt;/li&gt;

        &lt;li&gt;
&lt;strong&gt;Extendable:&lt;/strong&gt; Add audit logs, events, or bulk operations on top of the package.&lt;/li&gt;

      &lt;/ul&gt;
&lt;br&gt;
      &lt;h2&gt;Installation Guide&lt;/h2&gt;
&lt;br&gt;
      &lt;p&gt;Quick install steps — make sure your project uses PHP 8+ and a supported Laravel version (9–12):&lt;/p&gt;
&lt;br&gt;
      &lt;pre&gt;&lt;code&gt;composer require sowailem/ownable&lt;br&gt;
php artisan vendor:publish --provider="Sowailem\Ownable\OwnableServiceProvider" --tag="ownable-migrations"&lt;br&gt;
php artisan migrate&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
      &lt;p&gt;After migration you'll have the tables required by the package (see docs for exact schema).&lt;/p&gt;
&lt;br&gt;
      &lt;h2&gt;Getting Hands-On: Example Usage&lt;/h2&gt;
&lt;br&gt;
      &lt;p&gt;Below are typical steps to make a &lt;code&gt;User&lt;/code&gt; an owner and &lt;code&gt;Post&lt;/code&gt; an ownable entity.&lt;/p&gt;
&lt;br&gt;
      &lt;h3&gt;Model Setup&lt;/h3&gt;
&lt;br&gt;
      &lt;pre&gt;&lt;code&gt;// app/Models/User.php&lt;br&gt;
use Sowailem\Ownable\Traits\HasOwnables;&lt;br&gt;
use Sowailem\Ownable\Contracts\Owner as OwnerContract;

&lt;p&gt;class User extends Model implements OwnerContract {&lt;br&gt;
    use HasOwnables;&lt;br&gt;
}&lt;/p&gt;

&lt;p&gt;// app/Models/Post.php&lt;br&gt;
use Sowailem\Ownable\Traits\IsOwnable;&lt;br&gt;
use Sowailem\Ownable\Contracts\Ownable as OwnableContract;&lt;/p&gt;

&lt;p&gt;class Post extends Model implements OwnableContract {&lt;br&gt;
    use IsOwnable;&lt;br&gt;
}&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;
      &lt;h3&gt;Assigning &amp;amp; Checking Ownership&lt;/h3&gt;
&lt;br&gt;
      &lt;pre&gt;&lt;code&gt;// Assign ownership&lt;br&gt;
$user-&amp;gt;giveOwnershipTo($post);&lt;br&gt;
$post-&amp;gt;ownedBy($user);

&lt;p&gt;// Or use the facade&lt;br&gt;
Owner::give($user, $post);&lt;/p&gt;


&lt;p&gt;// Check ownership&lt;br&gt;&lt;br&gt;
if ($user-&amp;gt;owns($post)) {&lt;br&gt;&lt;br&gt;
    // do something&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
if ($post-&amp;gt;isOwnedBy($user)) {&lt;br&gt;&lt;br&gt;
    // do something else&lt;br&gt;&lt;br&gt;
}&lt;br&gt;&lt;br&gt;
Owner::check($user, $post); // returns boolean&lt;/p&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
      &lt;h3&gt;Transfer Ownership&lt;/h3&gt;
&lt;br&gt;&lt;br&gt;
      &lt;p&gt;Transferring ownership is a simple combination of revoke and give actions (or provided transfer helper if package supports it). Example:&lt;/p&gt;
&lt;br&gt;&lt;br&gt;
      &lt;pre&gt;&lt;code&gt;// Example transfer&lt;br&gt;&lt;br&gt;
$oldOwner-&amp;gt;revokeOwnershipOf($post);&lt;br&gt;&lt;br&gt;
$newOwner-&amp;gt;giveOwnershipTo($post);&lt;/code&gt;&lt;/pre&gt;
&lt;br&gt;&lt;br&gt;
      &lt;h2&gt;Real-World Use Cases&lt;/h2&gt;
&lt;br&gt;&lt;br&gt;
      &lt;ul&gt;


        &lt;li&gt;

&lt;strong&gt;Task management systems:&lt;/strong&gt; Assign, reassign and audit tasks across team members.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Marketplaces &amp;amp; e-commerce:&lt;/strong&gt; Sellers own product listings; transfer ownership on sales or administrative actions.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Document management:&lt;/strong&gt; Track custody of documents through reviews and approvals.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Multi-tenant platforms:&lt;/strong&gt; Map ownership to organizations, teams, or users for access and billing.&lt;/li&gt;


      &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
      &lt;h2&gt;Advanced Ideas &amp;amp; Best Practices&lt;/h2&gt;
&lt;br&gt;&lt;br&gt;
      &lt;p&gt;The package offers a strong base. Here are suggested extensions and practices to make ownership production-ready:&lt;/p&gt;
&lt;br&gt;&lt;br&gt;
      &lt;ul&gt;


        &lt;li&gt;

&lt;strong&gt;Ownership History:&lt;/strong&gt; Keep an audit table to record every &lt;code&gt;assigned&lt;/code&gt;, &lt;code&gt;revoked&lt;/code&gt;, and &lt;code&gt;transferred&lt;/code&gt; event. This is invaluable for debugging and compliance.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Events &amp;amp; Listeners:&lt;/strong&gt; Fire events like &lt;code&gt;OwnershipAssigned&lt;/code&gt; and &lt;code&gt;OwnershipTransferred&lt;/code&gt; so other systems (notifications, webhooks, analytics) can react.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Bulk/Batched Transfers:&lt;/strong&gt; For mass migrations, use queued jobs or bulk DB operations to avoid timeouts and keep data consistent.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Soft Deletes:&lt;/strong&gt; Decide how soft-deleted owners/ownables should behave. Consider cascading ownership or reassigning automatically.&lt;/li&gt;


        &lt;li&gt;

&lt;strong&gt;Testing:&lt;/strong&gt; Create unit tests for common flows: give, revoke, transfer, and permission checks.&lt;/li&gt;


      &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
      &lt;h2&gt;Implementation Tips &amp;amp; Gotchas&lt;/h2&gt;
&lt;br&gt;&lt;br&gt;
      &lt;ul&gt;


        &lt;li&gt;Be explicit about ownership uniqueness: can multiple owners own the same resource? If not, enforce DB constraints or app logic.&lt;/li&gt;


        &lt;li&gt;Design your UI to confirm transfers and explain consequences (especially for destructive operations).&lt;/li&gt;


        &lt;li&gt;When integrating with permissions, separate "ownership" from "authorization": owning a resource is not automatically equivalent to having all permissions over it unless you design it so.&lt;/li&gt;


      &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
      &lt;h2&gt;Why Developers Should Care&lt;/h2&gt;
&lt;br&gt;&lt;br&gt;
      &lt;p&gt;Adopting Laravel Ownable reduces boilerplate and enforces a standard ownership pattern across projects. It helps teams move faster, reduces bugs around ownership logic, and creates a clear place to extend for audits, reports, and business rules.&lt;/p&gt;
&lt;br&gt;&lt;br&gt;
    &lt;br&gt;&lt;br&gt;
      &lt;strong&gt;Quick checklist to adopt Ownable in your project&lt;/strong&gt;&lt;br&gt;&lt;br&gt;
      &lt;ul&gt;


        &lt;li&gt;Install and migrate the package.&lt;/li&gt;


        &lt;li&gt;Annotate Owner and Ownable models with the provided traits &amp;amp; contracts.&lt;/li&gt;


        &lt;li&gt;Write tests for ownership actions (give, check, revoke, transfer).&lt;/li&gt;


        &lt;li&gt;Optionally add events &amp;amp; an audit table for history.&lt;/li&gt;


        &lt;li&gt;Document ownership semantics in your codebase README.&lt;/li&gt;


      &lt;/ul&gt;
&lt;br&gt;&lt;br&gt;
    &lt;br&gt;&lt;br&gt;
      &lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;br&gt;&lt;br&gt;
      &lt;p&gt;Laravel Ownable solves a recurring problem in application design: mapping and managing ownership relationships. It's intentionally minimal and approachable, and it's a great base to build richer ownership features (audit, events, bulk operations). If you want a consistent, testable, and reusable ownership layer across your Laravel apps, Ownable is worth trying.&lt;/p&gt;`

</description>
      <category>laravel</category>
    </item>
  </channel>
</rss>
