{"id":20795659,"url":"https://github.com/graze/dal","last_synced_at":"2025-08-03T17:35:52.068Z","repository":{"id":62512400,"uuid":"21624107","full_name":"graze/dal","owner":"graze","description":"Data Access Layer","archived":false,"fork":false,"pushed_at":"2020-01-27T15:52:53.000Z","size":447,"stargazers_count":8,"open_issues_count":2,"forks_count":0,"subscribers_count":16,"default_branch":"master","last_synced_at":"2025-04-16T03:21:37.425Z","etag":null,"topics":["data-access-layer","php"],"latest_commit_sha":null,"homepage":null,"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/graze.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":"2014-07-08T18:11:40.000Z","updated_at":"2022-07-13T07:14:06.000Z","dependencies_parsed_at":"2022-11-02T12:48:31.882Z","dependency_job_id":null,"html_url":"https://github.com/graze/dal","commit_stats":null,"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graze%2Fdal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graze%2Fdal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graze%2Fdal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graze%2Fdal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graze","download_url":"https://codeload.github.com/graze/dal/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":252638603,"owners_count":21780618,"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","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":["data-access-layer","php"],"created_at":"2024-11-17T16:23:10.592Z","updated_at":"2025-05-06T07:06:22.480Z","avatar_url":"https://github.com/graze.png","language":"PHP","readme":"# DAL (Data Access Layer)\n\n\u003cimg src=\"diagram.png\" alt=\"Graze.com\" align=\"right\" width=240/\u003e\n\n[![Travis branch](https://img.shields.io/travis/graze/dal/master.svg?style=flat-square)]()\n[![Scrutinizer](https://img.shields.io/scrutinizer/g/graze/dal.svg?style=flat-square)]()\n[![Scrutinizer Coverage](https://img.shields.io/scrutinizer/coverage/g/graze/dal.svg?style=flat-square)]()\n[![PHP Version](https://img.shields.io/badge/php-\u003e=5.5-blue.svg?style=flat-square)]()\n[![Packagist](https://img.shields.io/packagist/l/graze/dal.svg?style=flat-square)]()\n[![Packagist](https://img.shields.io/packagist/v/graze/dal.svg?style=flat-square)]()\n\u003cbr/\u003e\n\n**DAL** is a data access layer for PHP, built to add an additional layer of\nabstraction between your application and persistence layers. The main goal of\nthis library is to allow use of multiple persistence layers, each potentially\nemploying different abstraction patterns, under a *single* interface.\n\nThe [data mapper pattern][data-mapper] is great for keeping the particulars of\ndata persistence hidden behind its interfaces. DAL improves upon this\nabstraction to include multiple persistence layers while providing underlying\nsupport for patterns other than data mapper (e.g.\n[active record][active-record]).\n\nWe're using this in-house to move our application towards a more manageable data\nmapper layer rather than our current active record implementation. This will be\nour interface into persistence across our PHP applications for the foreseeable\nfuture. We will continue to use our active record implementation underneath DAL\nuntil we decide to remove it completely, at which point DAL will stay put.\n\nThe main interface of DAL mimics the API of Doctrine ORM, with similarly named\n`getRepository()`, `persist()` and `flush()` methods. The repositories exposed\nthrough the `getRepository()` method even implement Doctrine's\n`ObjectRepository`, all with the aim of having a common ground with one of the\nmost feature-complete data mapper libraries for PHP.\n\nIt can be installed in whichever way you prefer, but we recommend\n[Composer][packagist].\n```json\n{\n    \"require\": {\n        \"graze/dal\": \"^1.0\"\n    }\n}\n```\n```bash\n$ composer require graze/dal\n```\n\n## Documentation\n\n- [Getting started with Eloquent](#getting-started-with-eloquent)\n- [Getting started with Doctrine](#getting-started-with-doctrine)\n- [Getting started with PDO](#getting-started-with-pdo)\n- [Relationships](#relationships)\n  - [Many to many relationships](#many-to-many-relationships)\n- [Using Multiple Adapters](#using-multiple-adapters)\n- [Database Support](#database-support)\n\n## Getting started with Eloquent\n\nUsing Eloquent with DAL requires the `illuminate/eloquent` package. You may also find the following resources helpful if\nyou're using Eloquent outside of Laravel: [How to use Eloquent outside of Laravel](https://laracasts.com/lessons/how-to-use-eloquent-outside-of-laravel), [Using Eloquent outside Laravel](https://vkbansal.me/blog/using-eloquent-outside-laravel/).\n\n#### Setting up the DalManager\n```php\nuse Graze\\Dal\\Adapter\\Orm\\EloquentOrmAdapter;\n\n$eloquentAdapter = EloquentOrmAdapter::createFromYaml(/*Eloquent DB Connection*/, ['path/to/config/eloquent.yml']);\n$dal = new DalManager([$eloquentAdapter]);\n```\n\nWe've got a `DalManager` object setup in our application, now we need to write some configuration for our entities:\n\n#### Writing the config\n\nAdapters come with two methods of configuration `createFromYaml` and `createFromArray`, in this documentation all examples are\nin YAML, but you can just use an array or anything that can convert into an array.\n\n```yaml\nApp\\Entity\\Product:\n    record: App\\Eloquent\\Product\n    adapter: Graze\\Dal\\Adapter\\Orm\\EloquentOrmAdapter\n    repository: App\\Repository\\ProductRepository\n    table: products\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        name:\n            mapsTo: name\n            type: string\n```\n\nThis is the config for a basic `Product` entity in our application. It's configured with the following fields:\n\n- `record` - This is the class provided by your persistence layer, in this case an Eloquent model.\n- `adapter` - This is the adapter this entity will be managed by.\n- `repository` (optional) - This is the custom repository class for this entity, DAL provides a generic repository if you don't specify one here.\n- `table` - This field is specific to the adapter, in this case we need to provide our Eloquent model with the table name for this entity.\n- `fields` - Defines each field on the entity, the `mapsTo` field refers to the property on the underlying Eloquent model that we're going to use for this field.\n\n#### Generating the classes\n\nWith this setup, we don't actually need to write any PHP code for our entity, DAL can generate it all for us. By running this command,\nDAL will generate an entity class, a repository and the underlying Eloquent model we need to get started.\n\n```bash\n$ bin/dal generate path/to/config/eloquent.yml App src\n```\n\n#### Using the DalManager\n\nWe've now got everything we need to start using our entity, which is done like so:\n\n```php\n$product = $dalManager-\u003egetRepository('App\\Entity\\Product')-\u003efind(1);\necho $product-\u003egetName();\n```\n\n## Getting started with Doctrine\n\nGetting started with Doctrine is very similar to Eloquent. The key differences are that DAL does not currently support\ngenerating the underlying Doctrine classes and configurationg for you, so you will need to write that yourself. You will\nalso need the `doctrine/orm` package.\n\n#### Setting up the DalManager\n\n```php\nuse Graze\\Dal\\Adapter\\Orm\\DoctrineOrmAdapter;\nuse Doctrine\\ORM\\EntityManager;\n\n$em = new EntityManager(); // see Doctrine's documentation for setting this up\n$doctrineAdapter = DoctrineOrmAdapter::createFromYaml($em, ['path/to/config/doctrine.yml']);\n$dal = new DalManager([$doctrineAdapter]);\n```\n\n#### Writing the config\n\n```yaml\nApp\\Entity\\Product:\n    record: App\\Doctrine\\Product\n    repository: App\\Repository\\ProductRepository\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        name:\n            mapsTo: name\n            type: string\n```\n\nYou will also need to write the Doctrine config for the underlying Doctrine entity.\n\n#### Generating the DAL entities and repositories\n\n```bash\n$ bin/dal generate path/to/config/doctrine.yml App src\n```\n\n**Note:** Generating Doctrine entities is currently **not supported**. You will have to write those yourself.\n\n#### Using the DalManager\n\n```php\n$product = $dalManager-\u003egetRepository('App\\Entity\\Product')-\u003efind(1);\necho $product-\u003egetName();\n```\n\n## Getting started with PDO\n\nDAL also has a very plain `PdoAdapter` if you don't need the features that ORMs come with but you still want\na sensible set of interfaces for managing your data. This does rely on the `aura/sql` package though, so make sure you \nhave that configured as a dependency of your app.\n\n#### Setting up the DalManager\n\n```php\nuse Graze\\Dal\\Adapter\\Pdo\\PdoAdapter;\nuse Aura\\Sql\\ExtendedPdo;\n\n$pdo = new ExtendedPdo(); // @see https://github.com/auraphp/Aura.Sql#lazy-connection-instance for setting this up\n$pdoAdapter = PdoAdapter::createFromYaml($pdo, ['path/to/config/pdo.yml']);\n$dal = new DalManager([$pdoAdapter]);\n```\n\n#### Writing the config\n\n```yaml\nApp\\Entity\\Product:\n    table: products\n    repository: App\\Repository\\ProductRepository\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        name:\n            mapsTo: name\n            type: string\n```\n\nNotice that there's no `record` field here, as there is no underlying model or record class with PDO this is unnecessary.\n\n#### Generating the DAL entities and repositories\n\nThere's no records/models to generate, so we just need to generate the DAL entities and repositories by running:\n\n```bash\n$ bin/dal generate path/to/config/pdo.yml App src\n```\n\n#### Using the DalManager\n\n```php\n$product = $dalManager-\u003egetRepository('App\\Entity\\Product')-\u003efind(1);\necho $product-\u003egetName();\n```\n\n## Relationships\n\nRelationships between entities should be defined at the DAL level and not in the underlying persistence layers. This is\nto facilitate entities being managed by different adapters.\n\n```yaml\nApp\\Entity\\Customer:\n    record: App\\Eloquent\\Customer\n    repository: App\\Repository\\CustomerRepository\n    table: customers\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        firstName:\n            mapsTo: first_name\n            type: string\n        lastName:\n            mapsTo: last_name\n            type: string\n    related:\n        orders:\n            type: oneToMany\n            entity: App\\Entity\\Order\n            foreignKey: customer_id\n            collection: true\n\nApp\\Entity\\Order:\n    record: App\\Eloquent\\Order\n    table: orders\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        price:\n            mapsTo: price\n            type: float\n    related:\n        customer:\n            type: manyToOne\n            entity: App\\Entity\\Customer\n            localKey: customer_id\n```\n\nThis example shows a simple relationship between a Customer and an Order. The Customer owns many Orders and so has a `oneToMany`\ntype with the Order entity, using the `customer_id` field on the orders table as a foreign key and we denote that this will\nbe a collection of entities.\n\nOn the Order entity configuration, we have a single Customer field defined as `manyToOne` as an Order belongs to a Customer\nand this uses the `customer_id` field on the orders table as the local key for determining which Customer owns this Order.\n\nThe `localKey` and `foreignKey` refer to fields on the database tables themselves, not the DAL entities or underlying persistence\nlayer entities. For this reason, relationships are currently only supported where on at least one side of the relationship there is an entity using SQL as its underlying\nstorage mechanism.\n\nThe example above shows the `manyToOne` and `oneToMany` relationship types, there is also `manyToMany`.\n\n#### Many to many relationships\n\nMany to many relationships require two entities and a pivot table that stores the relationship between them:\n\n```yaml\nApp\\Entity\\Order:\n    record: App\\Eloquent\\Order\n    table: orders\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        price:\n            mapsTo: price\n            type: float\n    related:\n        customer:\n            type: manyToOne\n            entity: App\\Entity\\Customer\n            localKey: customer_id\n        products:\n            type: manyToMany\n            entity: App\\Entity\\Product\n            pivot: order_item\n            localKey: order_id\n            foreignKey: product_id\n            collection: true\n```\n\nHere we have extended our Order entity to relate to many Products and of course, a single Product can also belong to many\nOrders.\n\nAs with other relationships we define the `type` and the `entity`, then we need to define the `pivot` table and the two keys,\n`localKey` and `foreignKey` that are on the pivot table. The `localKey` being the field storing the ID for the entity this\nconfiguration is for, in this case Order, and the `foreignKey` being the field storing the ID for the entity that we're\nrelating to, in this case Product.\n\n```bash\n$ bin/dal generate path/to/config/eloquent.yml App src\n```\n\n```php\n$customer = $dalManager-\u003egetRepository('App\\Entity\\Customer')-\u003efindBy(['email' =\u003e 'customer@example.com']);\n$orders = $customer-\u003egetOrders();\n\nforeach ($orders as $order) {\n    echo $order-\u003egetPrice();\n}\n```\n\n## Using Multiple Adapters\n\n```php\nuse Graze\\Dal\\Adapter\\Pdo\\PdoAdapter;\nuse Graze\\Dal\\Adapter\\Orm\\EloquentOrmAdapter;\nuse Aura\\Sql\\ExtendedPdo;\n\n$pdoAdapter = PdoAdapter::createFromYaml(new ExtendedPdo(/*see Aura docs*/), ['path/to/config/pdo.yml']);\n$eloquentAdapter = EloquentOrmAdapter::createFromYaml(/* see eloquent docs */, ['path/to/config/eloquent.yml']);\n$dalManager = new DalManager([$pdoAdapter, $eloquentAdapter]);\n```\n\nNow that we've got a DalManager setup with two configured adapters, we can write config to setup two entities with\ndifferent adapters and create relationships between them:\n\n```yaml\n# eloquent.yml\nApp\\Entity\\Customer:\n    record: App\\Eloquent\\Customer\n    repository: App\\Repository\\CustomerRepository\n    table: customers\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        firstName:\n            mapsTo: first_name\n            type: string\n        lastName:\n            mapsTo: last_name\n            type: string\n    related:\n        orders:\n            type: oneToMany\n            entity: App\\Entity\\Order\n            foreignKey: customer_id\n            collection: true\n\n# pdo.yml\nApp\\Entity\\Order:\n    table: orders\n    fields:\n        id:\n            mapsTo: id\n            type: int\n        price:\n            mapsTo: price\n            type: float\n    related:\n        customer:\n            type: manyToOne\n            entity: App\\Entity\\Customer\n            localKey: customer_id\n```\n\nNow we can generate all the entities, repositories and records we need:\n\n```bash\n$ bin/dal generate path/to/config/eloquent.yml App src\n```\n\nAnd use just like we have in all the previous examples:\n\n```php\n$customer = $dalManager-\u003egetRepository('App\\Entity\\Customer')-\u003efindBy(['email' =\u003e 'customer@example.com']);\n$orders = $customer-\u003egetOrders();\n\nforeach ($orders as $order) {\n    echo $order-\u003egetPrice();\n}\n```\n\nThis allows us to have different data handled by different adapters and storage mechanisms but create relationships\nbetween them through a single interface. How each entity is managed behind the scenes is abstracted away from our\nhigh-level code.\n\nThis opens up possibilities such as:\n\n```php\nuse Graze\\Dal\\Adapter\\Orm\\EloquentOrmAdapter;\nuse App\\Dal\\Adapter\\HttpAdapter;\n\n$httpAdapter = HttpAdapter::createFromYaml(new GuzzleHttp\\Client(), ['path/to/config/http.yml']);\n$eloquentAdapter = EloquentOrmAdapter::createFromYaml(/* see eloquent docs */, ['path/to/config/eloquent.yml']);\n$dalManager = new DalManager([$httpAdapter, $eloquentAdapter]);\n```\n\n## Database Support\n\nIn theory, DAL supports any database that is supported by the underlying persistence layers, Doctrine, Eloquent etc. However\nDAL only officially supports MySQL. This is because the code that handles the relationship types does currently rely on SQL\nqueries written within DAL which have only been tested on MySQL.\n\nIf you're working with a database that is supported by your persistence layer, do give it a go, in 90% of cases it will probably\nwork great. We will work to officially support other databases in the future.\n\n## Contributing \u0026 Support\n\nIf you have a support query, please open an issue and label it as 'support'. If you'd like to contribute, please\nopen a PR or an issue to discuss it first. Documentation contributions are incredibly welcome.\n\n#### Development\n\nThere's a docker-compose file that you can use to spin up an environment for development and testing:\n\n```bash\n$ make install\n$ make test\n```\n\n## License\nThe content of this library is released under the **MIT License** by\n**Nature Delivered Ltd**.\u003cbr/\u003e You can find a copy of this license in\n[`LICENSE`][license] or at http://opensource.org/licenses/mit.\n\n\u003c!-- Project links --\u003e\n[travis]: https://travis-ci.org/graze/dal\n[travis-master]: https://travis-ci.org/graze/dal.png?branch=master\n[packagist]: https://packagist.org/packages/graze/dal\n\n\u003c!-- References --\u003e\n[data-mapper]: http://en.wikipedia.org/wiki/Data_mapper_pattern\n[active-record]: http://en.wikipedia.org/wiki/Active_record_pattern\n[doctrine-orm]: http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/\n\n\u003c!-- Files --\u003e\n[license]: /LICENSE\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraze%2Fdal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraze%2Fdal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraze%2Fdal/lists"}