{"id":27366864,"url":"https://github.com/calebdw/laravel-sql-entities","last_synced_at":"2025-12-24T19:17:37.301Z","repository":{"id":287511390,"uuid":"964813451","full_name":"calebdw/laravel-sql-entities","owner":"calebdw","description":":books: Manage SQL entities in Laravel with ease!","archived":false,"fork":false,"pushed_at":"2025-12-15T00:33:26.000Z","size":120,"stargazers_count":29,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-12-17T15:11:54.439Z","etag":null,"topics":["database","database-functions","database-procedures","database-triggers","database-views","laravel","materialized-views","php","sql","sql-entity","views"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/calebdw.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"calebdw"}},"created_at":"2025-04-11T20:40:53.000Z","updated_at":"2025-12-15T00:33:24.000Z","dependencies_parsed_at":"2025-04-12T07:25:32.485Z","dependency_job_id":"5f28a2e1-1621-40be-a3bc-774ca12c38fe","html_url":"https://github.com/calebdw/laravel-sql-entities","commit_stats":null,"previous_names":["calebdw/laravel-sql-entities"],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/calebdw/laravel-sql-entities","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebdw%2Flaravel-sql-entities","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebdw%2Flaravel-sql-entities/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebdw%2Flaravel-sql-entities/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebdw%2Flaravel-sql-entities/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/calebdw","download_url":"https://codeload.github.com/calebdw/laravel-sql-entities/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/calebdw%2Flaravel-sql-entities/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28005981,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-12-24T02:00:07.193Z","response_time":83,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["database","database-functions","database-procedures","database-triggers","database-views","laravel","materialized-views","php","sql","sql-entity","views"],"created_at":"2025-04-13T06:40:29.371Z","updated_at":"2025-12-24T19:17:37.295Z","avatar_url":"https://github.com/calebdw.png","language":"PHP","funding_links":["https://github.com/sponsors/calebdw"],"categories":[],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n  \u003cp\u003e\n    \u003cimg src=\"/art/sql-entities.webp\" alt=\"SQL Entities\" width=\"40%\"\u003e\n  \u003c/p\u003e\n  \u003cp\u003eManage SQL entities in \u003ca href=\"https://laravel.com\"\u003eLaravel\u003c/a\u003e with ease!\u003c/p\u003e\n  \u003cp\u003e\n    \u003ca href=\"https://github.com/calebdw/laravel-sql-entities/actions/workflows/tests.yml\"\u003e\u003cimg src=\"https://github.com/calebdw/laravel-sql-entities/actions/workflows/tests.yml/badge.svg\" alt=\"Test Results\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://codecov.io/github/calebdw/laravel-sql-entities\"\u003e\u003cimg src=\"https://codecov.io/github/calebdw/laravel-sql-entities/graph/badge.svg?token=RPLQKWDM5G\" alt=\"Code Coverage\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://github.com/calebdw/laravel-sql-entities\"\u003e\u003cimg src=\"https://img.shields.io/github/license/calebdw/laravel-sql-entities\" alt=\"License\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/calebdw/laravel-sql-entities\"\u003e\u003cimg src=\"https://img.shields.io/packagist/v/calebdw/laravel-sql-entities.svg\" alt=\"Packagist Version\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://packagist.org/packages/calebdw/laravel-sql-entities\"\u003e\u003cimg src=\"https://img.shields.io/packagist/dt/calebdw/laravel-sql-entities.svg\" alt=\"Total Downloads\"\u003e\u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\nLaravel's schema builder and migration system are great for managing tables and\nindexes---but offer no built-in support for other SQL entities, such as\n(materialized) views, procedures, functions, and triggers.\nThese often get handled via raw SQL in migrations, making them hard to manage,\nprone to unknown conflicts, and difficult to track over time.\n\n`laravel-sql-entities` solves this by offering:\n\n- 📦 Class-based definitions: bringing views, functions, triggers, and more into your application code.\n- 🧠 First-class source control: you can easily track changes, review diffs, and resolve conflicts.\n- 🧱 Decoupled grammars: letting you support multiple drivers without needing dialect-specific SQL.\n- 🔁 Lifecycle hooks: run logic at various points, enabling logging, auditing, and more.\n- 🚀 Batch operations: easily create or drop all entities in a single command or lifecycle event.\n- 🧪 Testability: definitions are just code so they’re easy to test, validate, and keep consistent.\n\nWhether you're managing reporting views, business logic functions, or automation\ntriggers, this package helps you treat SQL entities like real, versioned parts\nof your codebase---no more scattered SQL in migrations!\n\n\u003e [!NOTE]\n\u003e Migration rollbacks are not supported since the definitions always reflect the latest state.\n\u003e\n\u003e [\"We're never going backwards. You only go forward.\" -Taylor Otwell](https://www.twitch.tv/theprimeagen/clip/DrabAltruisticEggnogVoHiYo-f6CVkrqraPsWrEht)\n\n## 📦 Installation\n\nFirst pull in the package using Composer:\n\n```bash\ncomposer require calebdw/laravel-sql-entities\n```\n\n\u003c!-- And then publish the package's configuration file: --\u003e\n\u003c!----\u003e\n\u003c!-- ```bash --\u003e\n\u003c!-- php artisan vendor:publish --provider=\"CalebDW\\SqlEntities\\ServiceProvider\" --\u003e\n\u003c!-- ``` --\u003e\n\nThe package looks for SQL entities under `database/entities/` so you might need to add\na namespace to your `composer.json` file, for example:\n\n```diff\n{\n  \"autoload\": {\n    \"psr-4\": {\n      \"App\\\\\": \"app/\",\n+     \"Database\\\\Entities\\\\\": \"database/entities/\",\n      \"Database\\\\Factories\\\\\": \"database/factories/\",\n      \"Database\\\\Seeders\\\\\": \"database/seeders/\"\n    }\n  }\n}\n```\n\n\u003e [!TIP]\n\u003e This package looks for any files matching `database/entities` in the application's\n\u003e base path. This means it should automatically work for a modular setup where\n\u003e the entities might be spread across multiple directories.\n\n\u003c!-- ## Configuration --\u003e\n\n## 🛠️ Usage\n\n### 🧱 SQL Entities\n\nTo get started, create a new class in a `database/entities/` directory\n(structure is up to you) and extend the appropriate entity class (e.g. `View`, etc.).\n\nFor example, to create a view for recent orders, you might create the following class:\n\n```php\n\u003c?php\n\nnamespace Database\\Entities\\Views;\n\nuse App\\Models\\Order;\nuse CalebDW\\SqlEntities\\View;\nuse Illuminate\\Database\\Query\\Builder;\nuse Override;\n\n// will create a view named `recent_orders_view`\nclass RecentOrdersView extends View\n{\n    #[Override]\n    public function definition(): Builder|string\n    {\n        return Order::query()\n            -\u003eselect(['id', 'customer_id', 'status', 'created_at'])\n            -\u003ewhere('created_at', '\u003e=', now()-\u003esubDays(30))\n            -\u003etoBase();\n\n        // could also use raw SQL\n        return \u003c\u003c\u003c'SQL'\n            SELECT id, customer_id, status, created_at\n            FROM orders\n            WHERE created_at \u003e= NOW() - INTERVAL '30 days'\n            SQL;\n    }\n}\n```\n\nYou can also override the name and connection:\n\n```php\n\u003c?php\nclass RecentOrdersView extends View\n{\n    protected ?string $name = 'other_name';\n    // also supports schema\n    protected ?string $name = 'other_schema.other_name';\n\n    protected ?string $connection = 'other_connection';\n}\n```\n\n#### 🔁 Lifecycle Hooks\n\nYou can also use the provided lifecycle hooks to run logic before or after an entity is created or dropped.\nReturning `false` from the `creating` or `dropping` methods will prevent the entity from being created or dropped, respectively.\n\n```php\n\u003c?php\nuse Illuminate\\Database\\Connection;\n\nclass RecentOrdersView extends View\n{\n    // ...\n\n    #[Override]\n    public function creating(Connection $connection): bool\n    {\n        if (/** should not create */) {\n            return false;\n        }\n\n        /** other logic */\n\n        return true;\n    }\n\n    #[Override]\n    public function created(Connection $connection): void\n    {\n        $this-\u003econnection-\u003estatement(\u003c\u003c\u003cSQL\n            GRANT SELECT ON TABLE {$this-\u003ename()} TO other_user;\n            SQL);\n    }\n\n    #[Override]\n    public function dropping(Connection $connection): bool\n    {\n        if (/** should not drop */) {\n            return false;\n        }\n\n        /** other logic */\n\n        return true;\n    }\n\n    #[Override]\n    public function dropped(Connection $connection): void\n    {\n        /** logic */\n    }\n}\n```\n\n#### ⚙️ Handling Dependencies\n\nEntities may depend on one another (e.g., a view that selects from another view).\nTo support this, each entity can declare its dependencies using the `dependencies()` method:\n\n```php\n\u003c?php\n\nclass RecentOrdersView extends View\n{\n    #[Override]\n    public function dependencies(): array\n    {\n        return [OrdersView::class];\n    }\n}\n```\n\nThe manager will ensure that dependencies are created in the correct order, using a topological sort behind the scenes.\nIn the example above, `OrdersView` will be created before `RecentOrdersView` automatically.\n\n#### 📑 View\n\nThe `View` class is used to create views in the database.\nIn addition to the options above, you can use the following options to further customize the view:\n\n```php\n\u003c?php\n\nclass RecentOrdersView extends View\n{\n    // to create a recursive view\n    protected bool $recursive = true;\n    // adds a `WITH CHECK OPTION` clause to the view\n    protected string|true|null $checkOption = 'cascaded';\n    // can provide explicit column listing\n    protected ?array $columns = ['id', 'customer_id', 'status', 'created_at'];\n}\n```\n\nAdditionally, you can start a query against the view using the `query()` method:\n\n```php\n\u003c?php\n\nRecentOrdersView::query()\n    -\u003ewhere('created_at', '\u003e=', now()-\u003esubDays(30))\n    -\u003eget();\n```\n\n\u003c!-- #### 💿 Materialized View --\u003e\n\u003c!----\u003e\n#### 📐 Function\n\nThe `Function_` class is used to create functions in the database.\n\n\u003e [!TIP]\n\u003e The class is named `Function_` as `function` is a reserved keyword in PHP.\n\nIn addition to the options above, you can use the following options to further customize the function:\n\n```php\n\u003c?php\n\nnamespace Database\\Entities\\Functions;\n\nuse CalebDW\\SqlEntities\\Function_;\n\nclass Add extends Function_\n{\n    /** If the function aggregates. */\n    protected bool $aggregate = false;\n\n    protected array $arguments = [\n        'integer',\n        'integer',\n    ];\n\n    /** The language the function is written in. */\n    protected string $language = 'SQL';\n\n    /** The function return type. */\n    protected string $returns = 'integer';\n\n    #[Override]\n    public function definition(): string\n    {\n        return \u003c\u003c\u003c'SQL'\n            RETURN $1 + $2;\n            SQL;\n    }\n}\n```\n\nLoadable functions are also supported:\n\n```php\n\u003c?php\n\nnamespace Database\\Entities\\Functions;\n\nuse CalebDW\\SqlEntities\\Function_;\n\nclass Add extends Function_\n{\n    protected array $arguments = [\n        'integer',\n        'integer',\n    ];\n\n    /** The language the function is written in. */\n    protected string $language = 'c';\n\n    protected bool $loadable = true;\n\n    /** The function return type. */\n    protected string $returns = 'integer';\n\n    #[Override]\n    public function definition(): string\n    {\n        return 'c_add';\n    }\n}\n```\n\n\u003c!-- #### 📤 Procedure --\u003e\n\u003c!----\u003e\n\n#### ⚡ Trigger\n\nThe `Trigger` class is used to create triggers in the database.\nIn addition to the options above, you can use the following options to further customize the trigger:\n\n```php\n\u003c?php\n\nnamespace Database\\Entities\\Triggers;\n\nuse CalebDW\\SqlEntities\\Trigger;\n\nclass AccountAuditTrigger extends Trigger\n{\n    // if the trigger is a constraint trigger\n    // PostgreSQL only\n    protected bool $constraint = false;\n\n    protected string $timing = 'AFTER';\n\n    protected array $events = ['UPDATE'];\n\n    protected string $table = 'accounts';\n\n    #[Override]\n    public function definition(): string\n    {\n        return $this-\u003edefinition ?? \u003c\u003c\u003c'SQL'\n            EXECUTE FUNCTION record_account_audit();\n            SQL;\n    }\n}\n```\n\n\u003c!-- #### 🔢 Sequence --\u003e\n\u003c!----\u003e\n\u003c!-- #### 🧳 Domain --\u003e\n\u003c!----\u003e\n\u003c!-- #### 🧬 Type --\u003e\n\u003c!----\u003e\n\u003c!-- #### 🛡 Policy --\u003e\n\n### 🧠 Manager\n\nThe `SqlEntityManager` singleton is responsible for creating and dropping SQL entities at runtime.\nYou can interact with it directly, or use the `SqlEntity` facade for convenience.\n\n```php\n\u003c?php\nuse CalebDW\\SqlEntities\\Facades\\SqlEntity;\nuse CalebDW\\SqlEntities\\SqlEntityManager;\nuse CalebDW\\SqlEntities\\View;\n\n// Create a single entity by class or instance\nSqlEntity::create(RecentOrdersView::class);\nresolve(SqlEntityManager::class)-\u003ecreate(RecentOrdersView::class);\nresolve('sql-entities')-\u003ecreate(new RecentOrdersView());\n\n// Similarly, you can drop a single entity using the class or instance\nSqlEntity::drop(RecentOrdersView::class);\n\n// Create or drop all entities\nSqlEntity::createAll();\nSqlEntity::dropAll();\n\n// You can also filter by type or connection\nSqlEntity::createAll(types: View::class, connections: 'reporting');\nSqlEntity::dropAll(types: View::class, connections: 'reporting');\n```\n\n#### ♻️ `withoutEntities()`\n\nSometimes you need to run a block of logic (like renaming a table column) *without certain SQL entities present*.\nThe `withoutEntities()` method temporarily drops the selected entities, executes your callback, and then recreates them afterward.\n\nIf the database connection supports **schema transactions**, the entire operation is wrapped in one.\n\n```php\n\u003c?php\nuse CalebDW\\SqlEntities\\Facades\\SqlEntity;\nuse Illuminate\\Database\\Connection;\n\nSqlEntity::withoutEntities(function (Connection $connection) {\n    $connection-\u003egetSchemaBuilder()-\u003etable('orders', function ($table) {\n        $table-\u003erenameColumn('old_customer_id', 'customer_id');\n    });\n});\n```\n\nYou can also restrict the scope to certain entity types or connections:\n\n```php\n\u003c?php\nuse CalebDW\\SqlEntities\\Facades\\SqlEntity;\nuse Illuminate\\Database\\Connection;\n\nSqlEntity::withoutEntities(\n    callback: function (Connection $connection) {\n        $connection-\u003egetSchemaBuilder()-\u003etable('orders', function ($table) {\n            $table-\u003erenameColumn('old_customer_id', 'customer_id');\n        });\n    },\n    types: [RecentOrdersView::class, RecentHighValueOrdersView::class],\n    connections: ['reporting'],\n);\n```\n\nAfter the callback, all affected entities are automatically recreated in dependency order.\n\n### 💻 Console Commands\n\nThe package provides console commands to create and drop your SQL entities.\n\n```bash\nphp artisan sql-entities:create [entities] [--connection=CONNECTION ...]\n\n# Create all entities\nphp artisan sql-entities:create\n# Create a specific entity\nphp artisan sql-entities:create 'Database\\Entities\\Views\\RecentOrdersView'\n# Create all entities on a specific connection\nphp artisan sql-entities:create -c reporting\n\n# Similarly, drop all entities\nphp artisan sql-entities:drop\n```\n\n### 🚀 Automatic syncing when migrating (Optional)\n\nYou may want to automatically drop all SQL entities before migrating, and then\nrecreate them after the migrations are complete. This is helpful when the entities\ndepend on schema changes. To do this, register the built-in subscriber in a service provider:\n\n```php\n\u003c?php\nuse CalebDW\\SqlEntities\\Listeners\\SyncSqlEntities;\nuse Illuminate\\Support\\Facades\\Event;\nuse Illuminate\\Support\\ServiceProvider;\n\nclass AppServiceProvider extends ServiceProvider\n{\n    public function boot(): void\n    {\n        Event::subscribe(SyncSqlEntities::class);\n    }\n}\n```\n\nThe listener will also create all entities if there's no pending migrations,\nensuring any new entities are created automatically.\n\n## 🤝 Contributing\n\nThank you for considering contributing! You can read the contribution guide [here](CONTRIBUTING.md).\n\n## ⚖️ License\n\nThis is open-sourced software licensed under the [MIT license](LICENSE).\n\n## 🔀 Alternatives\n\n- [laravel-sql-views](https://github.com/stats4sd/laravel-sql-views)\n- [laravel-migration-views](https://github.com/staudenmeir/laravel-migration-views)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebdw%2Flaravel-sql-entities","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcalebdw%2Flaravel-sql-entities","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcalebdw%2Flaravel-sql-entities/lists"}