{"id":13684238,"url":"https://github.com/josbeir/cakephp-filesystem","last_synced_at":"2025-12-13T00:41:47.275Z","repository":{"id":57001629,"uuid":"135139607","full_name":"josbeir/cakephp-filesystem","owner":"josbeir","description":"Filesystem plugin for CakePHP","archived":false,"fork":false,"pushed_at":"2023-12-28T14:59:37.000Z","size":172,"stargazers_count":20,"open_issues_count":4,"forks_count":10,"subscribers_count":6,"default_branch":"3.0","last_synced_at":"2024-10-11T17:39:02.371Z","etag":null,"topics":[],"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/josbeir.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}},"created_at":"2018-05-28T09:27:18.000Z","updated_at":"2023-03-14T16:07:58.000Z","dependencies_parsed_at":"2024-04-10T04:38:11.048Z","dependency_job_id":"a14c37bd-9ce2-449d-8291-a2bade299b78","html_url":"https://github.com/josbeir/cakephp-filesystem","commit_stats":{"total_commits":66,"total_committers":8,"mean_commits":8.25,"dds":0.4696969696969697,"last_synced_commit":"b9757e38b30617260ad3206a85f755beafc1a3cd"},"previous_names":[],"tags_count":12,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josbeir%2Fcakephp-filesystem","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josbeir%2Fcakephp-filesystem/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josbeir%2Fcakephp-filesystem/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josbeir%2Fcakephp-filesystem/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/josbeir","download_url":"https://codeload.github.com/josbeir/cakephp-filesystem/tar.gz/refs/heads/3.0","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":224224786,"owners_count":17276428,"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":[],"created_at":"2024-08-02T14:00:31.376Z","updated_at":"2025-12-13T00:41:47.243Z","avatar_url":"https://github.com/josbeir.png","language":"PHP","funding_links":[],"categories":["File Manipulation"],"sub_categories":[],"readme":"[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE.txt)\n[![Build Status](https://travis-ci.org/josbeir/cakephp-filesystem.svg?branch=master)](https://travis-ci.org/josbeir/cakephp-filesystem)\n[![codecov](https://codecov.io/gh/josbeir/cakephp-filesystem/branch/master/graph/badge.svg)](https://codecov.io/gh/josbeir/cakephp-filesystem)\n[![Latest Stable Version](https://poser.pugx.org/josbeir/cakephp-filesystem/v/stable)](https://packagist.org/packages/josbeir/cakephp-filesystem)\n[![Total Downloads](https://poser.pugx.org/josbeir/cakephp-filesystem/downloads)](https://packagist.org/packages/josbeir/cakephp-filesystem)\n\n# Filesystem plugin for CakePHP\n\nCakePHP filesystem plugin using [Flysystem](http://flysystem.thephpleague.com/docs/) as it's backend.\n\n\u003c!-- TOC --\u003e\n\n- [Filesystem plugin for CakePHP](#filesystem-plugin-for-cakephp)\n  - [Why](#why)\n  - [Requirements](#requirements)\n  - [Installation](#installation)\n  - [Configuration](#configuration)\n  - [Simple upload example](#simple-upload-example)\n    - [Result](#result)\n  - [Entity properties](#entity-properties)\n  - [Recreating entities](#recreating-entities)\n  - [Using your own entities](#using-your-own-entities)\n    - [Example on using Cake ORM entities instead of the built entity class](#example-on-using-cake-orm-entities-instead-of-the-built-entity-class)\n  - [Formatters](#formatters)\n    - [Setting up formatters](#setting-up-formatters)\n    - [Creating a custom formatter class](#creating-a-custom-formatter-class)\n      - [Example custom formatter](#example-custom-formatter)\n      - [Using the custom formatter class in your application](#using-the-custom-formatter-class-in-your-application)\n  - [Methods](#methods)\n  - [Events](#events)\n  - [Extras](#extras)\n    - [Changing the hashing algorithm used in entities](#changing-the-hashing-algorithm-used-in-entities)\n    - [Accessing the Flysytem object](#accessing-the-flysytem-object)\n  - [Contribute](#contribute)\n\n\u003c!-- /TOC --\u003e\n\n## Why\n\n- Easy access to Flysystem filesystems in your application\n- Upload normalization, accepts $_FILES, Zend\\Diactoros\\UploadedFile or just a path on the local FS\n- Files are represented by customisable and json serialisable entities, Multiple files are returned in a custom [Collection](https://book.cakephp.org/3.0/en/core-libraries/collections.html) instance.\n- A trait is available, use it everywhere in your app\n- Customizable path/filename formatting during upload, custom formatters are possible, ships with a Default and EntityFormatter.\n\n## Requirements\n\n* CakePHP 4.x\n* PHP 7.2\n\n## Installation\n\nYou can install this plugin into your CakePHP application using [composer](http://getcomposer.org).\n\nThe recommended way to install composer packages is:\n\n```\ncomposer require josbeir/cakephp-filesystem\n```\n\n## Configuration\n\nA filesystem configuration array should be available in your Configure instance. You can create a config/filesystems.php file with following content\nMake sure to load the file in your bootstrap.php using ```Configure::load('filesystems', 'default');```.\n\nThe configuration options defined for each 'filestem' are passed directly to the Filesystem.php class. A `default` configuration must be set when using FilesystemAwareTrait / FilesystemRegistry classes\n\n```php\n\u003c?php\nreturn [\n    'Filesystem' =\u003e [\n        'default' =\u003e [\n            'adapter' =\u003e 'League\\Flysystem\\Local\\LocalFilesystemAdapter', // default\n            'adapterArguments' =\u003e [ WWW_ROOT . 'files' ]\n        ],\n        'other' =\u003e [\n            'adapter' =\u003e 'League\\Flysystem\\Local\\LocalFilesystemAdapter',\n            'adapterArguments' =\u003e [ WWW_ROOT . 'cache' ],\n            'entityClass' =\u003e '\\My\\Cool\\EntityClass',\n            'formatter' =\u003e '\\My\\Cool\\Formatter'\n        ]\n    ]\n];\n```\n\n## Simple upload example\n\nFilesystem instances can be accessed from everywhere where you either use the **FilesystemAwareTrait** and calling ```MyClass::getFilesystem($configKey)``` or the ```FilesystemRegistry::get()```\n\nIn this example we are using a fictive 'myfs' filesystem definition, if you leave that empty the default FS will be used when calling ``getFilesystem()``.\n\nUpload data submitted in POST:\n```php\n [\n    'tmp_name' =\u003e '/tmp/blabla',\n    'filename' =\u003e 'lame filename.png',\n    'error' =\u003e 0,\n    'size' =\u003e 1337,\n    'type' =\u003e 'image/png'\n]\n```\n\nExample controller:\n```php\n\u003c?php\nnamespace App\\Controller;\n\nuse Josbeir\\Filesystem\\FilesystemAwareTrait;\n\nclass MyController extends AppController {\n\n    use FilesystemAwareTrait;\n\n    public function upload()\n    {\n        $fileEntity = $this-\u003egetFilesystem('myfs')-\u003eupload($this-\u003erequest-\u003egetData('upload'));\n\n        debug($fileEntity);\n    }\n}\n```\n\n### Result\n\nThe result from the above example will output a file entity class\n\n```php\nobject(Josbeir\\Filesystem\\FileEntity) {\n\n    'uuid' =\u003e 'a105663a-f1a5-40ab-8716-fac211fb01fd',\n    'path' =\u003e 'articles/now_im_called_bar.png',\n    'filename' =\u003e 'lame filename.png',\n    'filesize' =\u003e (int) 28277,\n    'mime' =\u003e 'image/png',\n    'hash' =\u003e '6b16dafccd78955892d3eae973b49c6c',\n    'meta' =\u003e null,\n    'created' =\u003e object(Cake\\I18n\\Time) {\n\n        'time' =\u003e '2018-05-27T15:31:54+00:00',\n        'timezone' =\u003e '+00:00',\n        'fixedNowTime' =\u003e false\n\n    }\n\n}\n```\n\n\n## Entity properties\n\nA JsonSerializable FileEntity ArrayObject is returned when the file was successfully uploaded.\nProperties can be accessed, checked and manipulated using get** and set** and has**\n\n```php\n$entity-\u003ehasUuid('a105663a-f1a5-40ab-8716-fac211fb01fd');\n$entity-\u003egetUuid() // a105663a-f1a5-40ab-8716-fac211fb01fd\n$entity-\u003esetUuid('a105663a-f1a5-40ab-8716-fac211fb01fd');\n...\n...\n```\n\nCalling json_encode on the entity\n\n```json\n// json_encode($entitiy);\n{\n    \"uuid\": \"3ae258dd-ab1d-425c-b3b0-450f0c702d64\",\n    \"path\": \"dummy.png\",\n    \"filename\": \"dummy.png\",\n    \"size\": 59992,\n    \"mime\": \"image\\/png\",\n    \"hash\": \"3ba92ed92481b4fc68842a2b3dcee525\",\n    \"created\": \"2018-06-03T09:27:41+00:00\",\n    \"meta\": null\n}\n```\n\n## Recreating entities\n\nIf you for instance saved a file entity somwhere as a json object you could recreate the entity using `Filemanager::newEntity`\n\n```php\n$entity = $this-\u003egetFilesystem()-\u003enewEntity([\n    'uuid' =\u003e 'a105663a-f1a5-40ab-8716-fac211fb01fd',\n    'path' =\u003e 'articles/now_im_called_bar.png',\n    'filename' =\u003e 'lame filename.png',\n    'filesize' =\u003e 28277,\n    'mime' =\u003e 'image/png',\n    'hash' =\u003e '6b16dafccd78955892d3eae973b49c6c',\n    'created' =\u003e '2018-05-27T15:31:54+00:00',\n    \"meta\": [\n        \"extra\" =\u003e \"stuf\"\n    ]\n]);\n```\n\nRecreating a [Collection](https://book.cakephp.org/3.0/en/core-libraries/collections.html) of entities.\n\n```php\n$entities = FileEntityCollection::createFromArray($entities [, string $filesystem]);\n```\n\n## Using your own entities\n\nCreating your own entities is possible by implementing the FileEntityInterface class and setting the entity class FQCN in your configuration's ``entityClass`` key.\n\n### Example on using Cake ORM entities instead of the built entity class\n\nIf you want to store your entities in the ORM you can easily swap the entity class with an ORM one. The only requirement is that the entity implements the ``FileEntityInterface`` class.\n\n```php\nreturn [\n    'Filesystem' =\u003e [\n        'default' =\u003e [\n            'entityClass' =\u003e 'App\\Model\\Entity\\MyFileEntity'\n        ]\n]\n```\n\nThen make sure your ORM entity implements the FileEntityInterface and its required method 'getPath':\n\n```php\nnamespace App\\Model\\Entity;\n\nuse Cake\\ORM\\Entity;\nuse Josbeir\\Filesystem\\FileEntityInterface;\n\nclass MyFileEntity extends Entity implements FileEntityInterface\n{\n    public function getPath() : string\n    {\n        return $this-\u003epath;\n    }\n\n    public function setPath(string $path) : FileEntityInterface\n    {\n        $this-\u003eset('path', $path);\n\n        return $this;\n    }\n}\n```\n\nNow when uploading and using files you can work with ORM entities.\n\n## Formatters\n\nDuring upload a formatter is used to construct a path and filename. For instance, if you use the EntityFormatter you can use variables available in an entity to build the filename.\n\n```php\n$entity = $this-\u003ePosts-\u003eget(1);\n\n$fileEntity = $this-\u003egetFilesystem()-\u003eupload(TMP . 'myfile.png', [\n    'formatter' =\u003e 'Entity', // formatter to use\n    'data' =\u003e $entity // data to pass to the formatter\n]);\n```\nThe default EntityFormatter pattern is ``{entity-source}/{file-name}.{file-ext}`` which results in ``posts/myfile.png``\n\n### Setting up formatters\n\nFormatters are simple classes used to name and clean file paths during upload, this plugin currently comes with two formatters.\n\n* **DefaultFormatter**, this just returns the 'cleaned' filename\n* **EntityFormatter**, extends the default formatter, expects an EntityInterface as data and used to format filenames based on data from an entity.\n\n```php\n$entity = $this-\u003ePosts-\u003eget(1);\n\n$this-\u003egetFilesystem()\n    -\u003eupload(TMP . 'myfile.png', [\n        'formatter' =\u003e 'Entity',\n        'data' =\u003e $entity,\n        'pattern' =\u003e '{entity-source}/{date-y}-{date-m}-{date-d}-{file-name}-{custom}.{file-ext}',\n        'replacements' =\u003e [ 'custom' =\u003e 'key' ] // extra replacement patterns\n    ]);\n```\n\nShould result in something like ``posts/2018-05-26-myfile-key.png`` .\n\n### Creating a custom formatter class\n\nCreating your own formatter class is pretty straightforward. The class should implement ``FormatterInterface`` Check the ``DefaultFormatter`` or ``EntityFormatter``classes for more information.\n\n#### Example custom formatter\n```php\n\u003c?php\nnamespace \\Path\\To\\Formatters\n\nuse Josbeir\\Filesystem\\DefaultFormatter;\n\nclass MyFormatter extends DefaultFormatter\n{\n    // Extra settings?\n    protected $_defaultConfig = [\n        'mysetting1' =\u003e 'hello'\n        'mysetting2' =\u003e 'world'\n    ];\n\n    public function getPath() : string\n    {\n        $setting = $this-\u003egetConfig('mysetting1');\n        $setting2 = $this-\u003egetConfig('mysetting2');\n\n        return $setting . DS . $setting2 . DS . $this-\u003egetBaseName();\n    }\n}\n```\n\n#### Using the custom formatter class in your application\n\nThe formatter FQCN can be set in the filesystem config or whenever you call setFormatter.\n\n```php\n$file = $this-\u003egetFilesystem()\n    -\u003esetFormatter('\\Path\\To\\Formatters\\MyFormatter')\n    -\u003eupload($file, [\n        'mysetting2' =\u003e 'cool',\n    ]);\n\ndebug($file-\u003egetPath()) // hello/cool/myfile.png\n```\n\n## Methods\n\nThe Filesystem class itself implements a few convenience methods around the Flysystem filesystem class.\n\nOther methods are proxied over. If you wish to use the Flysystem instance directly then please use getDisk().\n\n```php\n// Upload a file\n// Will fire Filesystem.beforeUpload and Filesystem.afterUpload\n$this-\u003egetFilesystem()-\u003eupload($data, $config);\n\n// Upload multiple files and returns a FileEntityCollection\n// Will fire Filesystem.beforeUpload and Filesystem.afterUpload (after each file upload)\n$this-\u003egetFilesystem()-\u003euploadMany($files, $config);\n\n// Copy an entity\n// Will fire Filesystem.beforeCopy and Filesystem.afterCopy\n$this-\u003egetFilesystem()-\u003ecopy($entity, $config);\n\n// Rename an entity\n// Will fire Filesystem.beforeRename and Filesystem.afterRename\n$this-\u003egetFilesystem()-\u003erename($entity, $config);\n\n// Delete an entity from the FS\n// Will fire Filesystem.beforeDelete and Filesystem.afterDelete\n$this-\u003egetFilesystem()-\u003edelete($entity);\n\n// Check if a file entity exists on the FS\n$this-\u003egetFilesystem()-\u003eexists($entity);\n\n// Get Flysystem FS instance\n$this-\u003egetFilesystem()-\u003egetDisk();\n\n// Get Flysystem adatapter\n$this-\u003egetFilesystem()-\u003egetAdapter();\n\n// Set the formatter class name to be used\n$this-\u003egetFilesystem()-\u003esetFormatter($name);\n\n// Return a new formatter instance\n$this-\u003egetFilesystem()-\u003enewFormatter($filename, $config);\n\n// Reset formatter and adapter to default configuration\n$this-\u003egetFilesystem()-\u003ereset();\n```\n\n## Events\n\nEvents are dispatched when performing an operation on a file entity.\nCurrently the following events are implemented:\n\n| Name | Passed params | Stoppable?  |\n|------| ---------- | ----------- |\n| Filesystem.beforeUpload | FileSource, Formatter | No\n| Filesystem.afterUpload | FileEntity, FileSource | No\n| Filesystem.beforeDelete | FileEntity | Yes\n| Filesystem.afterDelete | FileEntity | No\n| Filesystem.beforeRename | FileEntity, new path | Yes\n| Filesystem.afterRename | FileEntity | No\n| Filesystem.beforeCopy | FileEntity, destination path | Yes\n| Filesystem.afterCopy | (new) FileEntity, (old) FileEntity | No\n\n## Extras\n\n### Changing the hashing algorithm used in entities\n\nOptions can be passed to the FileSourceNormalizer using the 'normalizer' parameter in the filesystem instance config:\n\n```php\n\u003c?php\nreturn [\n    'Filesystem' =\u003e [\n        'default' =\u003e [\n            'adapter' =\u003e 'League\\Flysystem\\Local\\LocalFilesystemAdapter',\n            'adapterArguments' =\u003e [ WWW_ROOT . 'assets' . DS . 'local' ],\n            'normalizer' =\u003e [\n                'hashingAlgo' =\u003e 'sha1'\n            ]\n        ]\n    ]\n]\n```\n\n### Accessing the Flysytem object\n\nBecause this plugin is using flysystem at its core one could easily integrate with other flysystem compatible code.\nAccessing the flysystem directly can be done using ``Filesystem::getDisk()``.\n\nAs an example we can work with [Admad's glide plugin](https://github.com/ADmad/cakephp-glide) and use configured filesystems as source and cache:\n\nFirst set up your default and cache configurations:\n\n```php\n\u003c?php\nreturn [\n    'Filesystem' =\u003e [\n        'default' =\u003e [\n            'adapter' =\u003e 'League\\Flysystem\\Local\\LocalFilesystemAdapter',\n            'adapterArguments' =\u003e [ WWW_ROOT . 'assets' . DS . 'local' ],\n            'entityClass' =\u003e 'App\\Model\\Entity\\FilesystemFile'\n        ],\n        'cache' =\u003e [\n            'adapter' =\u003e 'League\\Flysystem\\Local\\LocalFilesystemAdapter',\n            'adapterArguments' =\u003e [ WWW_ROOT . 'assets' . DS . 'cached' ],\n        ]\n    ]\n];\n```\n\nThen set up the Glide middleware using the configured filesystems mentioned above:\n\n```php\nuse FilesystemAwareTrait;\n\n..\n..\n\n$routes-\u003eregisterMiddleware('glide', new GlideMiddleware([\n    'server' =\u003e [\n        'source' =\u003e $this-\u003egetFilesystem()-\u003egetDisk(),\n        'cache' =\u003e $this-\u003egetFilesystem('cache')-\u003egetDisk()\n    ]\n]));\n\n$routes-\u003escope('/images', [ 'cache' =\u003e false ], function ($routes) {\n    $routes-\u003eapplyMiddleware('glide');\n    $routes-\u003econnect('/*');\n});\n```\n\n## Contribute\n\nBefore submitting a PR make sure:\n\n- [PHPUnit](http://book.cakephp.org/3.0/en/development/testing.html#running-tests)\nand [CakePHP Code Sniffer](https://github.com/cakephp/cakephp-codesniffer) tests pass\n- [Codecov Code Coverage ](https://codecov.io/gh/josbeir/cakephp-filesystem) does not drop\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosbeir%2Fcakephp-filesystem","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjosbeir%2Fcakephp-filesystem","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosbeir%2Fcakephp-filesystem/lists"}