{"id":16789680,"url":"https://github.com/ryangjchandler/orbit","last_synced_at":"2026-04-01T17:49:47.099Z","repository":{"id":39882960,"uuid":"349793148","full_name":"ryangjchandler/orbit","owner":"ryangjchandler","description":"A flat-file database driver for Eloquent. 🗄","archived":false,"fork":false,"pushed_at":"2026-03-18T22:12:50.000Z","size":1317,"stargazers_count":922,"open_issues_count":9,"forks_count":39,"subscribers_count":8,"default_branch":"1.x","last_synced_at":"2026-03-19T09:48:44.696Z","etag":null,"topics":[],"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/ryangjchandler.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"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":"ryangjchandler"}},"created_at":"2021-03-20T17:32:49.000Z","updated_at":"2026-03-18T22:04:20.000Z","dependencies_parsed_at":"2024-06-18T15:19:13.106Z","dependency_job_id":"6e50ef85-fbc1-42f0-b1a6-245777c6bf9b","html_url":"https://github.com/ryangjchandler/orbit","commit_stats":{"total_commits":200,"total_committers":15,"mean_commits":"13.333333333333334","dds":"0.19499999999999995","last_synced_commit":"fab8cd6837cd8a8c3291ae08f9a62d44a99c13b1"},"previous_names":[],"tags_count":45,"template":false,"template_full_name":null,"purl":"pkg:github/ryangjchandler/orbit","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryangjchandler%2Forbit","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryangjchandler%2Forbit/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryangjchandler%2Forbit/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryangjchandler%2Forbit/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ryangjchandler","download_url":"https://codeload.github.com/ryangjchandler/orbit/tar.gz/refs/heads/1.x","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ryangjchandler%2Forbit/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31290622,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-01T13:12:26.723Z","status":"ssl_error","status_checked_at":"2026-04-01T13:12:25.102Z","response_time":53,"last_error":"SSL_read: 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":[],"created_at":"2024-10-13T08:28:01.266Z","updated_at":"2026-04-01T17:49:47.079Z","avatar_url":"https://github.com/ryangjchandler.png","language":"PHP","funding_links":["https://github.com/sponsors/ryangjchandler"],"categories":[],"sub_categories":[],"readme":"![Orbit](./art/orbit.png)\n\n\u003cp align=\"center\"\u003e\n    \u003ca href=\"https://laravel.com\"\u003e\u003cimg alt=\"Laravel v9.x\" src=\"https://img.shields.io/badge/Laravel-v9.x-FF2D20?style=for-the-badge\u0026logo=laravel\"\u003e\u003c/a\u003e\n    \u003ca href=\"https://php.net\"\u003e\u003cimg alt=\"PHP 8.0\" src=\"https://img.shields.io/badge/PHP-8.0-777BB4?style=for-the-badge\u0026logo=php\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nOrbit is a flat-file driver for Laravel Eloquent. It allows you to replace your generic database with real files that you can manipulate using the methods you're familiar with.\n\n## Installation\n\nTo install Orbit, run the following command in your project:\n\n```bash\ncomposer require ryangjchandler/orbit\n```\n\n## Usage\n\nTo begin using Orbit, create a Laravel model and use the `Orbit\\Concerns\\Orbital` trait.\n\n```php\nclass Post extends Model\n{\n    use \\Orbit\\Concerns\\Orbital;\n}\n```\n\nThe `Orbital` trait is responsible for hooking into the Eloquent lifecycle and ensuring all of your interactions are handled correctly.\n\n### Defining the Schema\n\nJust like a database migration, you need to define the different pieces of data that your Orbit model can have. Add a `public static function schema(Blueprint $table)` method to your model.\n\nThis method will need to accept an instance of `Illuminate\\Database\\Schema\\Blueprint`, just like a migration.\n\n```php\nuse Illuminate\\Database\\Schema\\Blueprint;\n\nclass Post extends Model\n{\n    use \\Orbit\\Concerns\\Orbital;\n\n    public static function schema(Blueprint $table)\n    {\n        $table-\u003estring('title');\n        $table-\u003estring('slug');\n        $table-\u003etimestamp('published_at');\n    }\n}\n```\n\n\u003e If some of your data is optional, make sure the corresponding column is `nullable`.\n\n### Storing content\n\nBy default, all content is stored inside of a `content` folder in the root of your application. If you wish to change this, publish the `orbit.php` configuration file and change the `orbit.paths.content` option.\n\nOrbit will transform the base name of your model into a pluralized snake-cased string and use that as the main folder name, e.g. `Post` -\u003e `content/posts`, `PostCategory` =\u003e `content/post_categories`.\n\n\u003e 🚨 Changing the name of a model will prevent Orbit from finding any existing records in the old folder. If you wish to change the name of the folder, overwrite the `public static function getOrbitalName` method on your model class and return the old name instead.\n\nAny time you call `Model::create()`, `Model::update` or `Model::delete`, Orbit will intercept those calls and forward to the necessary driver method. The driver is then responsible for performing the necessary file system calls.\n\n### Changing the primary key\n\nJust like a normal Eloquent model, you can change the primary key of your Orbit model. Overwrite the `Model::getKeyName` method and return the name of your new model.\n\n```php\nclass Post extends Model\n{\n    use Orbital;\n\n    public function getKeyName()\n    {\n        return 'slug';\n    }\n    \n    public function getIncrementing()\n    {\n        return false;\n    }\n}\n```\n\n\u003e If your model's primary key (the key you defined in `getKeyName`) doesn't need to automatically increment, you should either define `public $incrementing = false` on the model or overwrite the `getIncrementing` method.\n\nStandard Orbit drivers will respect the new key name and use that when creating, updating and deleting files on disk, e.g. a `Post` with the slug `hello-world` will write to the `content/posts/hello-world.md` file.\n\n\u003e 🚨 Changing the key for a model after records already exist can cause damage. Be sure to rename your files afterwards so that Orbit doesn't create duplicate content.\n\n### Soft Deletes\n\nSince Orbit needs to update files on disk when your model is updated, the standard Eloquent `SoftDeletes` trait doesn't quite work. If you want to add soft delete support to your Orbit model, you can instead use the `Orbit\\Concerns\\SoftDeletes` trait.\n\nThis trait uses the Eloquent one under-the-hood, so you can still access all of your normal `SoftDeletes` methods, including `isForceDeleting()` and `forceDelete()`. \n\nThe Orbit version adds in the necessary hooks to perform file system operations as well as ensure you don't completely delete your content.\n\n### Validation Rules\n\nWhen dealing with [validation rules](https://laravel.com/docs/8.x/validation#available-validation-rules) that check against a database like [`exists`](https://laravel.com/docs/8.x/validation#rule-exists) and [`unique`](https://laravel.com/docs/8.x/validation#rule-unique), you should use the **fully-qualified namespace (FQN) of the model** instead of the table name.\n\nThis is because Orbit runs on a separate database connection - using the FQN will allow Laravel to correctly resolve the qualified table name.\n\n```php\nclass StorePostRequest extends FormRequest\n{\n    public function authorize(): bool\n    {\n        return true;\n    }\n\n    public function rules(): array\n    {\n        return [\n            'slug' =\u003e 'required|alpha_dash|unique:App\\Post,id',\n            // 'slug' =\u003e ['required', 'alpha_dash', Rule::unique(Post::class)],\n            'title' =\u003e 'required',\n            'description' =\u003e 'required',\n        ];\n    }\n  }\n```\n\n### Testing\n\nAs previously mentioned in the [Validation Rules](#validation-rules) section, Orbit operates on a custom connection called `orbit`. This means that Laravel's database testing utilities will work, as long as you specify the connection name.\n\n```php\n$this-\u003eassertDatabaseCount('posts', 5, 'orbit');\n\n$this-\u003eassertDatabaseHas('posts', [\n    'title' =\u003e 'Hello, world',\n    'slug' =\u003e 'hello-world',\n], 'orbit');\n```\n\n## Drivers\n\nOrbit is a driver-based package, making it very easy to change the storage format of your data.\n\nOut of the box, Orbit provides the following drivers:\n\n* `md` -\u003e `Orbit\\Drivers\\Markdown`\n* `json` =\u003e `Orbit\\Drivers\\Json`\n* `yaml` =\u003e `Orbit\\Drivers\\Yaml`\n\n### `md`\n\nThis is a Markdown that is capable of parsing Markdown files, as well as YAML front-matter.\n\nWhen Orbit loads files using this driver, it will map each front-matter key into a column in your models `schema`.\n\nBy default, the Markdown driver will also add a `TEXT content` column to your schema. This is used to store the Markdown body from the file.\n\n\u003e 💡 If you wish to customise the name of the `content` column, you can use the `Markdown::contentColumn()` method and provide a new column name. This is applied to all models that use the `Markdown` driver.\n\n### `json`\n\nThis is a JSON driver that is capable of parsing `.json` files. Each key in the file is mapped to a column in your schema.\n\n### `yaml`\n\nThis is a YAML driver that is capable of parsing `.yml` files. Each key in the file is mapped to a column in your schema.\n\n### Registering drivers\n\nYou can register custom Orbit drivers by using the `Orbit::extend` method. You should call this method from the `boot` method in a `ServiceProvider`.\n\n```php\n\\Orbit\\Facades\\Orbit::extend('json', function ($app) {\n    return new \\App\\Drivers\\JsonDriver($app);\n})\n```\n\nAll drivers must implement the `Orbit\\Contracts\\Driver` contract, or extend the `Orbit\\Drivers\\FileDriver` class. This enforces drivers to have at least 4 methods:\n\n```php\ninterface Driver\n{\n    public function shouldRestoreCache(string $directory): bool;\n\n    public function save(Model $model, string $directory): bool;\n\n    public function delete(Model $model, string $directory): bool;\n\n    public function all(string $directory): Collection;\n}\n```\n\nHere is what each method is used for:\n\n* `shouldRestoreCache` - used to determine if the file cache should be updated. \n* `save` - used to persist model changes to a file on disk, or create a new file.\n* `delete` - used to delete an existing file on disk\n* `all` - used to retrieve all records from disk and cache.\n\n### Extending `FileDriver`\n\nExtending the `Orbit\\Drivers\\FileDriver` class is useful when you want some of the heavy lifting done for you. To work with this base class, you should do the following:\n\n1. Implement an `extension(): string` method that returns the file extension as a string, i.e. `return 'md'` for `Markdown`.\n2. Implement a `dumpContent(Model $model): string` method. This method should return the updated content for the file.\n3. Implement a `parseContent(SplFileInfo $file): array` method. This method should return an array of `key =\u003e value` pairs, where each `key` is a column in the `schema`.\n\n### Changing drivers\n\nIf you wish to use a different driver for one of your models, you can add a `public static $driver` property to your model and set the value to the name of a driver.\n\n```php\nclass Post extends Model\n{\n    use Orbital;\n\n    public static $driver = 'json';\n}\n```\n\n\u003e Driver names are determined when they are registered with Orbit. You should always use the string name of the driver instead of the fully-qualified class name.\n\n### Disabling Orbit\n\nIf you have a model that uses the `Orbital` trait and would like to temporarily disable Orbit's functionality, you can override the `enableOrbit(): bool` method on your model:\n\n```php\nclass Post extends Model\n{\n    use Orbital;\n\n    public static function enableOrbit(): bool\n    {\n        return false;\n    }\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryangjchandler%2Forbit","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fryangjchandler%2Forbit","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fryangjchandler%2Forbit/lists"}