{"id":36977369,"url":"https://github.com/culturegr/presenter","last_synced_at":"2026-01-13T22:46:25.576Z","repository":{"id":37406086,"uuid":"221157020","full_name":"culturegr/presenter","owner":"culturegr","description":"Eloquent Model Presenters for your Laravel app","archived":false,"fork":false,"pushed_at":"2025-04-10T07:21:08.000Z","size":47,"stargazers_count":14,"open_issues_count":0,"forks_count":1,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-09-24T04:14:20.398Z","etag":null,"topics":["decorators","laravel","php","presenters"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/culturegr.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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}},"created_at":"2019-11-12T07:32:11.000Z","updated_at":"2025-04-10T07:19:59.000Z","dependencies_parsed_at":"2025-03-18T10:32:20.973Z","dependency_job_id":"3288b58e-ac71-4d93-840c-0f4135132daf","html_url":"https://github.com/culturegr/presenter","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/culturegr/presenter","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/culturegr%2Fpresenter","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/culturegr%2Fpresenter/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/culturegr%2Fpresenter/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/culturegr%2Fpresenter/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/culturegr","download_url":"https://codeload.github.com/culturegr/presenter/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/culturegr%2Fpresenter/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28403012,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-13T14:36:09.778Z","status":"ssl_error","status_checked_at":"2026-01-13T14:35:19.697Z","response_time":56,"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":["decorators","laravel","php","presenters"],"created_at":"2026-01-13T22:46:25.506Z","updated_at":"2026-01-13T22:46:25.567Z","avatar_url":"https://github.com/culturegr.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏺 Presenter\n\n[![Latest Version on Packagist][ico-version]][link-packagist]\n[![Total Downloads][ico-downloads]][link-downloads]\n![Github Actions](https://github.com/culturegr/presenter/actions/workflows/run-tests.yml/badge.svg)\n\n\nThis package provides an easy way to create Presenters that can be used to [decorate](https://en.wikipedia.org/wiki/Decorator_pattern) an Eloquent Model. It is heavily inspired by [Hemp Presenter](https://github.com/davidhemphill/presenter) and [Laravel API Resources](https://laravel.com/docs/6.x/eloquent-resources), however it comes with some key differences:\n - It provides an easy way to handle *paginated* models\n - It does not focus solely in JSON API responses but it serves as a *general purpose* decorator that can be used anywhere in the project\n\n## TL;DR\n\nA **Decorator** is an object that wraps another object in order to add functionality to the wrapped object. It also delegates calls to methods not available on the decorator to the class being decorated. Decorators can be useful when you need to modify the functionality of a class without relying on inheritance. You can use it to add optional features to your objects like logging, access-control, and things of that sort. A **Presenter** is a type of decorator used to present an object to the view of an application, such as a Blade view, or an API response.\n\n## Installation\n\nVia [Composer](https://getcomposer.org):\n\n``` bash\n$ composer require culturegr/presenter\n```\nIn Laravel 5.5+, the package's service provider should be [auto-discovered](https://laravel.com/docs/5.7/packages#package-discovery), so you won't need to register it. If for some reason you need to register it manually you can do so by adding it to the providers array in `config/app.php`:\n\n```php\n'providers' =\u003e [\n    // ...\n    CultureGr\\Presenter\\PresenterServiceProvider::class,\n],\n```\n\n## Usage\n\n### Creating Presenter Classes\n\nA Presenter class can be generated by running the `make:presenter` Artisan command:\n\n```bash\nphp artisan make:presenter UserPresenter\n```\n\nThis will generate an empty `Presenter` class inside of `app/Presenters`\n\n### Customizing Presenter Classes\n\nPresenters are simple classes designed to encapsulate complex or repetitive view logic. For example, here is a simple `UserPresenter` class:\n\n```php\n\u003c?php\n\nnamespace App\\Presenters;\n\nuse CultureGr\\Presenter\\Presenter;\n\nclass UserPresenter extends Presenter\n{\n\n    public function fullname()\n    {\n        return $this-\u003efirstname.' '.$this-\u003elastname;\n    }\n}\n```\n\nNote that the original model's properties (`firstname`, `lastname`) can be directly accessed using the `$this` variable. This is because the `Presenter` class automatically proxies property and method access down to the underlying model.\n\nThis class has a custom method `fullname` that can be called wherever an instance of this Presenter is used.\n\n```php\n$presentedUser-\u003efirstname; //=\u003e 'John'\n$presentedUser-\u003elastname; //=\u003e 'Doe'\n$presentedUser-\u003efullname() //=\u003e 'John Doe'\n```\n\nThe Presenter class requires you to implement an abstract `toArray` method which returns the array of attributes that should be used when the presenter is converted to an array or JSON. This ensures consistent behavior across all presenter classes.\n\n```php\n\u003c?php\n\nnamespace App\\Presenters;\n\nuse CultureGr\\Presenter\\Presenter;\n\nclass UserPresenter extends Presenter\n{\n    public function fullname()\n    {\n        return $this-\u003efirstname.' '.$this-\u003elastname;\n    }\n\n    public function toArray()\n    {\n        return [\n            'id' =\u003e $this-\u003eid,\n            'fullname' =\u003e $this-\u003efullname()\n             // ...\n        ];\n    }\n}\n```\n\n### Presenting Single Models\n\nOnce the presenter is defined, it may be used to create a presented model using the `make` factory method:\n\n```php\n$user = User::first();\n$presentedUser = UserPresenter::make($user);\n```\n\nThe presented model may be used anywhere in the project and can be passed to views, returned from controllers, or returned from API routes. Presenters implement `Arrayable`, `Jsonable`, `JsonSerializable`, and `ArrayAccess` interfaces, which means they can be:\n\n- Automatically converted to arrays when needed (no need to call `toArray()` explicitly)\n- Automatically converted to JSON when returned from routes (no need to call `toJson()` explicitly)\n- Accessed like arrays using square bracket notation (e.g., `$presenter['key']`)\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\User;\nuse App\\Presenters\\UserPresenter;\n\nclass UserController extends Controller\n{\n    public function show($id)\n    {\n        // No need to call toArray() - automatic conversion happens when needed\n        return view('users.show', [\n            'user' =\u003e UserPresenter::make(User::find($id))\n        ]);\n    }\n}\n```\n\n### Presenting Collections\n\nTo present a collection of models, the static `collection` method on the Presenter class can be used:\n\n```php\n$users = User::all();\n$presentedUsers = UserPresenter::collection($users);\n```\n\nThe collection of presented models may be used anywhere in the project. Thanks to the automatic conversion features, the collection can be directly returned from a route or controller without explicitly calling `toArray()`:\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\User;\nuse App\\Presenters\\UserPresenter;\n\nclass UserController extends Controller\n{\n    public function index()\n    {\n        $users = User::all();\n\n        return UserPresenter::collection($users);\n    }\n}\n```\n\nThe output will be something like this:\n\n```json\n[\n    {\"id\": \"1\", \"fullname\": \"John Doe\"},\n    {\"id\": \"2\", \"fullname\": \"Jane Doe\"}\n]\n```\n\n### Presenting Paginated Collections\n\nTo present a paginated collection of models with pagination metadata, the static `pagination` method on the Presenter class can be used:\n\n```php\n$users = User::paginate();\n$presentedUsers = UserPresenter::pagination($users);\n```\n\nThe paginated collection of presented models may be used anywhere in the project and can be directly returned from a route or controller:\n\n```php\n\u003c?php\n\nnamespace App\\Http\\Controllers;\n\nuse App\\Models\\User;\nuse App\\Presenters\\UserPresenter;\n\nclass UserController extends Controller\n{\n    public function index()\n    {\n        $users = User::paginate();\n\n        return UserPresenter::pagination($users);\n    }\n}\n```\n\nThe output will contain the presented models wrapped in a `data` key, along with `links` and `meta` keys containing pagination information:\n\n```json\n{\n    \"data\": [\n        {\"id\": \"1\", \"fullname\": \"John Doe\"},\n        {\"id\": \"2\", \"fullname\": \"Jane Doe\"}\n    ],\n    \"links\":{\n        \"first\": \"http://example.com/pagination?page=1\",\n        \"last\": \"http://example.com/pagination?page=1\",\n        \"prev\": null,\n        \"next\": null\n    },\n    \"meta\":{\n        \"current_page\": 1,\n        \"from\": 1,\n        \"last_page\": 1,\n        \"path\": \"http://example.com/pagination\",\n        \"per_page\": 15,\n        \"to\": 10,\n        \"total\": 10\n    }\n}\n```\n\n### Using the Presentable Trait\n\nThe package provides a `Presentable` trait that can be used to present models directly from the model instance. This allows for a more elegant syntax when presenting models, collections, and paginators.\n\nTo use the trait, first add it to your model:\n\n```php\n\u003c?php\n\nnamespace App\\Models;\n\nuse Illuminate\\Database\\Eloquent\\Model;\nuse CultureGr\\Presenter\\Presentable;\n\nclass User extends Model\n{\n    use Presentable;\n\n    // ...\n}\n```\n\nThen you can present the model directly using the `present` method:\n\n```php\n$user = User::first();\n$presentedUser = $user-\u003epresent(UserPresenter::class);\n```\n\nThis allows for a more fluent syntax when presenting models:\n\n```php\n$presentedUser = User::first()-\u003epresent(UserPresenter::class);\n```\n\nFor collections, you can use the `presentCollection` method directly on the collection:\n\n```php\n$users = User::all();\n$presentedUsers = $users-\u003epresentCollection(UserPresenter::class);\n```\n\nThis is equivalent to using the static `collection` method on the Presenter class, but provides a more fluent API.\n\nYou can also use the `presentCollection` method directly on a paginator instance:\n\n```php\n$users = User::paginate();\n$presentedUsers = $users-\u003epresentCollection(UserPresenter::class);\n```\n\nWhen used on a paginator, the `presentCollection` method automatically detects that it's being called on a paginator and returns a structured result with the presented models wrapped in a `data` key, along with `links` and `meta` keys containing pagination information.\n\n### Automatic Array and JSON Conversion\n\nPresenters now implement the necessary interfaces to be automatically converted to arrays or JSON when needed:\n\n- `Arrayable`: Allows automatic conversion to arrays\n- `Jsonable`: Allows automatic conversion to JSON strings\n- `JsonSerializable`: Ensures proper JSON serialization\n- `ArrayAccess`: Allows accessing presenters like arrays using square bracket notation\n\nThis means you no longer need to explicitly call `toArray()` or `toJson()` in most contexts:\n\n```php\n// Before\n$array = $presenter-\u003etoArray();\n$json = $presenter-\u003etoJson();\n\n// Now - automatic conversion happens when needed\n$array = $presenter; // Automatic conversion to array\n$json = json_encode($presenter); // Automatic conversion to JSON\nreturn $presenter; // Automatic conversion when returned from routes\n```\n\n### Array Access Support\n\nPresenters can now be accessed like arrays:\n\n```php\n$presenter = UserPresenter::make($user);\n$id = $presenter['id']; // Same as $presenter-\u003eid\n```\n\n### Abstract toArray Method\n\nThe `toArray()` method is now abstract, which means all presenter classes must implement it. This ensures consistent behavior across all presenters.\n\n### Note for Existing Users\n\nIf you're currently calling `toArray()` explicitly when using Presenters (e.g., `UserPresenter::make($user)-\u003etoArray()`), please note that these calls will continue to work as before. However, they are no longer necessary in most contexts due to the new automatic conversion feature. You can safely remove these explicit calls if desired, which will make your code cleaner and more concise.\n\n## Testing\n\n``` bash\n$ composer test\n```\n\n## License\n\nPlease see the [license file](LICENSE.md) for more information.\n\n[ico-version]: https://img.shields.io/packagist/v/culturegr/presenter.svg?style=flat-square\n[ico-downloads]: https://img.shields.io/packagist/dt/culturegr/presenter.svg?style=flat-square\n[ico-travis]: https://img.shields.io/travis/culturegr/presenter/master.svg?style=flat-square\n\n[link-packagist]: https://packagist.org/packages/culturegr/presenter\n[link-downloads]: https://packagist.org/packages/culturegr/presenter\n[link-travis]: https://travis-ci.org/culturegr/presenter\n\n## Credits\n\n* Huge shout out to [David Hemphill](https://github.com/davidhemphill)\n* Awesome Laravel/PHP community\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fculturegr%2Fpresenter","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fculturegr%2Fpresenter","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fculturegr%2Fpresenter/lists"}