{"id":36998001,"url":"https://github.com/griffin-php/griffin","last_synced_at":"2026-01-13T23:57:36.168Z","repository":{"id":51363958,"uuid":"357344849","full_name":"griffin-php/griffin","owner":"griffin-php","description":"Griffin is a Graph-Oriented Migration Framework for PHP","archived":false,"fork":false,"pushed_at":"2021-05-13T11:37:36.000Z","size":223,"stargazers_count":14,"open_issues_count":5,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-10T03:51:17.910Z","etag":null,"topics":["database","dependencies","framework","graph","graph-theory","migration","migrations","php"],"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/griffin-php.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-04-12T21:32:14.000Z","updated_at":"2022-02-07T15:11:34.000Z","dependencies_parsed_at":"2022-09-24T22:22:33.105Z","dependency_job_id":null,"html_url":"https://github.com/griffin-php/griffin","commit_stats":null,"previous_names":[],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/griffin-php/griffin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/griffin-php%2Fgriffin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/griffin-php%2Fgriffin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/griffin-php%2Fgriffin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/griffin-php%2Fgriffin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/griffin-php","download_url":"https://codeload.github.com/griffin-php/griffin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/griffin-php%2Fgriffin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28406009,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T21:51:37.118Z","status":"ssl_error","status_checked_at":"2026-01-13T21:45:14.585Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"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","dependencies","framework","graph","graph-theory","migration","migrations","php"],"created_at":"2026-01-13T23:57:35.574Z","updated_at":"2026-01-13T23:57:36.160Z","avatar_url":"https://github.com/griffin-php.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# griffin\n\n\u003cdiv\u003e\n  \u003cp align=\"center\"\u003e\u003cimg src=\"https://raw.githubusercontent.com/griffin-php/griffin/main/icon.svg\" width=\"200\"\u003e\u003c/p\u003e\n  \u003cp align=\"center\"\u003eGriffin is a Graph-Oriented Migration Framework for PHP\u003c/div\u003e\n\u003c/div\u003e\n\n[![Build Status](https://github.com/griffin-php/griffin/actions/workflows/test.yml/badge.svg?branch=main)](https://github.com/griffin-php/griffin/actions/workflows/test.yml?query=branch%3Amain)\n[![Latest Stable Version](https://poser.pugx.org/griffin/griffin/v/stable?format=flat)](https://packagist.org/packages/griffin/griffin)\n[![Codecov](https://codecov.io/gh/griffin-php/griffin/branch/main/graph/badge.svg)](https://codecov.io/gh/griffin-php/griffin)\n[![License](https://poser.pugx.org/griffin/griffin/license?format=flat)](https://packagist.org/packages/griffin/griffin)\n\n## TL;DR\n\nGriffin is a generic migration framework that uses graph theory to provision\nanything. It plans execution based on migration dependencies and runs them in\nthe correct order.\n\n```php\nuse FooBar\\Database\\Driver;\nuse Griffin\\Migration\\Container;\nuse Griffin\\Migration\\Migration;\nuse Griffin\\Planner\\Planner;\nuse Griffin\\Runner\\Runner;\n\n$driver = new Driver(); // Pseudo Database Driver\n\n$orders = (new Migration())\n    -\u003ewithName('orders')\n    -\u003ewithAssert(fn() =\u003e $driver-\u003etable-\u003ehas('orders'))\n    -\u003ewithUp(fn() =\u003e $driver-\u003etable-\u003ecreate('orders'))\n    -\u003ewithDown(fn() =\u003e $driver-\u003etable-\u003edrop('orders'));\n\n$items = (new Migration())\n    -\u003ewithName('items')\n    -\u003ewithDependencies(['orders'])\n    -\u003ewithAssert(fn() =\u003e $driver-\u003etable-\u003ehas('items'))\n    -\u003ewithUp(fn() =\u003e $driver-\u003etable-\u003ecreate('items'))\n    -\u003ewithDown(fn() =\u003e $driver-\u003etable-\u003edrop('items'));\n\n$container = (new Container())\n    -\u003eaddMigration($orders)\n    -\u003eaddMigration($items);\n\n$planner = new Planner($container);\n$runner  = new Runner($planner);\n\n$runner-\u003eup(); // create everything\n$runner-\u003edown(); // destroy everything\n\n$runner-\u003eup('items'); // create orders and items\n$runner-\u003edown('orders'); // destroy orders and items\n\n// create orders and items\n// regardless the order of elements informed\n$runner-\u003eup('items', 'orders');\n\n// Dry Run\n$runner-\u003esetDryRun();\n$runner-\u003eup(); // do nothing\n$runner-\u003edown(); // do nothing\n$runner-\u003eunsetDryRun();\n```\n\nYou might want to check\n[more examples](https://github.com/griffin-php/griffin-examples) to learn how to\ndefine migrations using Griffin.\n\n## Installation\n\nThis package uses [Composer](https://packagist.org/packages/griffin/griffin) as\ndefault repository. You can install it adding the name of package in `require`\nsection of `composer.json`, pointing to the latest stable version.\n\n```json\n{\n  \"require\": {\n    \"griffin/griffin\": \"^1.0\"\n  }\n}\n```\n\n### CLI\n\nThis package includes the Griffin framework. If you want a CLI to run your\nmigrations, please check\n[Griffin CLI](https://github.com/griffin-php/griffin-cli).\n\n## Introduction\n\nMigrations are tools to change system current state, adding (or removing)\nfeatures based on previous state. Generally, they are used to create database\nstructures from scratch, provisioning tables or columns using a step-by-step\napproach. There are standalone tools to run migrations, like Phinx. Also, there\nare other ones embedded into frameworks, like Laravel or Doctrine.\n\nIf we inspect them, they use a linear approach, where next state must *migrate*\nfrom current state. Migrations can be rolled back, so if we want to revert some\nchanges, we must *rollback* from current state to previous state. Each migration\nknows how to create and destroy itself.\n\nFor example, we have three migrations `A`, `B` and `C` created sequentially. If\nour current state is `A` and we must migrate to `C`, we must execute migrations\n`B` and `C`, in that order, respectively. If we want to rollback from `C` to\n`A`, we must execute them backwards, `B` and `A`. But if you want to execute\nmigrations `A` and `C`, because they are dependent, and ignore `B` for some\nreason, you can't. Even, if you want to rollback `C` and `A` ignoring `B`, you\nare locked.\n\nBringing to the world of database migrations, you can create migration `Orders`\nthat creates table into schema. Right after that, other developer creates a\nmigration called `Messages` without any dependency from `Orders`. Next, you\ncreate a migration named `Items` with a foreign key to `Orders`. Everything\nworks fine and you deploy them to *stage* environment on friday.\n\n```\n./migrations/001_Orders.php\n./migrations/002_Messages.php\n./migrations/003_Items.php\n```\n\nOn monday you find a problem with your migrations and you want to rollback. But\nyou don't want to remove `Messages` table because other developer is showing the\nnewest features to Product Owner.\n\nAnd here comes Griffin.\n\n## Description\n\nGriffin is a migration framework based on directed graphs, where each migration\ncan be migrated and rolled back independently. Also, you can define dependencies\nfor each migration and Griffin is responsible to plan the execution priority.\n\nBased on provisioning tools like Puppet and Terraform, Griffin can plan\nexecution and run it using graph theory, where each migration works like a\nvertice and dependencies define directed paths. Griffin searches for circular\ndependencies on planning and can automatically rollback changes if errors were\nfound.\n\nGriffin is a generic migration framework and it is not database focused. You are\nfree to use Griffin to provisioning what needed, like directory structures,\npackages, crawlers and even database schemas.\n\n## Usage\n\nEach migration must be defined using `Griffin\\Migration\\MigrationInterface`.\nMigrations must return its name with `getName` method and dependencies with\n`getDependencies`. Each migration must check if resource is created using\n`assert` method, returning a boolean as result. Also, they are responsible to\ncreate the resource using `up` method and to destroy using `down`. Griffin uses\nthese methods to plan and run migrations.\n\n```php\nnamespace FooBar\\Database\\Migration;\n\nuse FooBar\\Database\\Driver;\nuse Griffin\\Migration\\MigrationInterface;\n\nclass Items implements MigrationInterface\n{\n    public function __construct(\n        private Driver $driver,\n    ) {}\n\n    public function getName(): string\n    {\n        return self::class;\n    }\n\n    /**\n     * @return string[]\n     */\n    public function getDependencies(): array\n    {\n        return [\n            Order::class,\n            Product::class,\n        ];\n    }\n\n    public function assert(): bool\n    {\n        return $this-\u003edriver-\u003etable-\u003ehas('items');\n    }\n\n    public function up(): void\n    {\n        $this-\u003edriver-\u003etable-\u003ecreate('items');\n    }\n\n    public function down(): void\n    {\n        $this-\u003edriver-\u003etable-\u003edrop('items');\n    }\n}\n```\n\nYou can create objects from class `Griffin\\Migration\\Migration`, that implements\n`Griffin\\Migration\\MigrationInterface` and behaviors can be defined using\nimmutable methods.\n\n```php\nuse FooBar\\Database\\Driver;\nuse Griffin\\Migration\\Migration;\n\n$driver = new Driver();\n\n$migration = (new Migration())\n    -\u003ewithName('items')\n    -\u003ewithDependencies(['orders', 'products'])\n    -\u003ewithAssert(fn() =\u003e $driver-\u003etable-\u003ehas('items'))\n    -\u003ewithUp(fn() =\u003e $driver-\u003etable-\u003ecreate('items'))\n    -\u003ewithDown(fn() =\u003e $driver-\u003etable-\u003edrop('items'));\n```\n\n### Planning\n\nGriffin plans your migrations execution before running them using\n`Griffin\\Planner\\Planner`. Every migration must be added to\n`Griffin\\Migration\\Container` instances and attached to planner on construction.\n\n```php\nuse FooBar\\Database\\Migration;\nuse Griffin\\Migration\\Exception as MigrationException;\nuse Griffin\\Planner\\Exception as PlannerException;\nuse Griffin\\Planner\\Planner;\n\n$planner = new Planner();\n\n$planner-\u003egetContainer()\n    -\u003eaddMigration(new Migration\\Orders())\n    -\u003eaddMigration(new Migration\\Items())\n    -\u003eaddMigration(new Migration\\Products());\n\n/** @var Griffin\\Migration\\Container $migrations **/\n\ntry {\n    // plan up execution for every migration\n    $migrations = $planner-\u003eup();\n    // plan up execution for Orders and Items\n    $migrations = $planner-\u003eup(Migration\\Items::class)\n    // plan down execution\n    $migrations = $planner-\u003edown();\n} catch (PlannerException $e) {\n    // PlannerException::DEPENDENCY_CIRCULAR (Circular Dependency Found)\n    // PlannerException::DEPENDENCY_INVALID (Invalid Dependency Data Type)\n} catch (MigrationException $e) {\n    // MigrationException::NAME_UNKNOWN (Unknown Migration Name)\n    // MigrationException::NAME_DUPLICATED (Duplicated Migration Name)\n    // MigrationException::CALLABLE_UNKNOWN (Unknown Callable Function)\n}\n```\n\nYou can add migrations to container in any order, because dependencies are\nchecked on planning stage. Migration names are unique and must not be\nduplicated. Using objects from `Griffin\\Migration\\Migration` immutable class can\nthrow errors if callables were not defined.\n\nThis stage also searches for circular dependencies, where `A` depends of `B` and\n`B` depends of `A`. This type of requirement is not allowed and will rise an\nexception describing the problem.\n\n### Running\n\nAfter planning, Griffin runs migrations using `Griffin\\Runner\\Runner` class.\nInternally, Griffin plans migrations execution first and after that it will\nexecute running on second stage.\n\n```php\nuse FooBar\\Database\\Migration;\nuse Griffin\\Migration\\Exception as MigrationException;\nuse Griffin\\Planner\\Exception as PlannerException;\nuse Griffin\\Runner\\Exception as RunnerException;\nuse Griffin\\Runner\\Runner;\n\n$runner = new Runner();\n\n$runner-\u003egetPlanner()-\u003egetContainer()\n    -\u003eaddMigration(new Migration\\Orders())\n    -\u003eaddMigration(new Migration\\Items())\n    -\u003eaddMigration(new Migration\\Products());\n\ntry {\n    // run up for everything\n    $runner-\u003eup();\n    // run up for Orders and Items\n    $runner-\u003eup(Migration\\Items::class)\n    // run complete down\n    $runner-\u003edown();\n} catch (RunnerException $e) {\n    // RunnerException::ROLLBACK_CIRCULAR (Circular Rollback Found)\n} catch (PlannerException $e) {\n    // PlannerException::DEPENDENCY_CIRCULAR (Circular Dependency Found)\n    // PlannerException::DEPENDENCY_INVALID (Invalid Dependency Data Type)\n} catch (MigrationException $e) {\n    // MigrationException::NAME_UNKNOWN (Unknown Migration Name)\n    // MigrationException::NAME_DUPLICATED (Duplicated Migration Name)\n    // MigrationException::CALLABLE_UNKNOWN (Unknown Callable Function)\n}\n```\n\nFor every planned migration `Griffin\\Runner\\Runner` will execute migration `up`\nmethod if `assert` returns `false`. During a migration execution, errors can be\nraised and Griffin will try to automatically rollback executed migrations. If\nduring rollback from this migration Griffin finds another error, an exeception\nwill be throw.\n\nIf you want to rollback migrations manually, Griffin will use migration `assert`\nmethod to check if resource was created and if this method returns `true`,\nmigration method `down` will be called. As before, if Griffin finds an error it\nwill try to recreate resources.\n\n### Event Dispatcher\n\nLastly, Griffin use PSR-14 Event Dispatcher to trigger events after and before\nmigrations up and down. You can use it to create a logger, as example, using\n`league/event` package or any PSR-14 implementation.\n\n```php\nuse FooBar\\Database\\Migration;\nuse Griffin\\Event;\nuse Griffin\\Migration\\Container;\nuse Griffin\\Planner\\Planner;\nuse Griffin\\Runner\\Runner;\nuse League\\Event\\EventDispatcher;\n\n$container = new Container();\n$planner   = new Planner($container);\n$runner    = new Runner($planner);\n\n$logger = fn($event)\n    =\u003e printf(\"%s::%s\\n\", get_class($event), get_class($event-\u003egetMigration()));\n\n$dispatcher = new EventDispatcher(); // PSR-14\n\n$dispatcher-\u003esubscribeTo(Event\\Migration\\UpBefore::class, $logger);\n$dispatcher-\u003esubscribeTo(Event\\Migration\\UpAfter::class, $logger);\n\n$dispatcher-\u003esubscribeTo(Event\\Migration\\DownBefore::class, $logger);\n$dispatcher-\u003esubscribeTo(Event\\Migration\\DownAfter::class, $logger);\n\n$runner\n    -\u003esetEventDispatcher($dispatcher)\n    -\u003eaddMigration(new Migration\\Orders());\n\n$runner-\u003eup();\n$runner-\u003edown();\n\n// Griffin\\Event\\Migration\\UpBefore::Database\\Migration\\Table\\Item\n// Griffin\\Event\\Migration\\UpAfter::Database\\Migration\\Table\\Item\n// Griffin\\Event\\Migration\\DownBefore::Database\\Migration\\Table\\Item\n// Griffin\\Event\\Migration\\DownAfter::Database\\Migration\\Table\\Item\n```\n\n## Development\n\nYou can use Docker Compose to build an image and run a container to develop and\ntest this package.\n\n```bash\ndocker-compose build\ndocker-compose run --rm php composer install\ndocker-compose run --rm php composer test\n```\n\n## References\n\n* Wikipedia: [Graph Theory](https://en.wikipedia.org/wiki/Graph_theory)\n* Wikipedia: [Path on Graph Theory](https://en.wikipedia.org/wiki/Path_%28graph_theory%29)\n* Wikipedia: [Schema Migration](https://en.wikipedia.org/wiki/Schema_migration)\n\n## License\n\nThis package is opensource and available under MIT license described in\n[LICENSE](https://github.com/griffin-php/griffin/blob/main/LICENSE).\n\nIcons made by [Freepik](https://www.freepik.com) from\n[Flaticon](https://www.flaticon.com).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgriffin-php%2Fgriffin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgriffin-php%2Fgriffin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgriffin-php%2Fgriffin/lists"}