Storing file upload details in the database provide more flexibility and control over file handling and management. You can easily keep track of who uploaded this file and when.
In this tutorial, I show how you can upload file with validation and save it to the MySQL database in CakePHP 4 project.
Also, show how you can display stored files on the page.
Contents
- Create Table
- Database Configuration
- Create Model
- Create Controller
- Create Template
- Output
- Conclusion
1. Create Table
In the example, I am using files
table. It has the following structure –
CREATE TABLE `files` ( `id` int(11) NOT NULL, `filename` varchar(255) NOT NULL, `path` varchar(255) NOT NULL )
2. Database Configuration
- Open
config/app_local.php
file. - Specify your database configuration details in the
Datasources
default
.
'Datasources' => [ 'default' => [ 'host' => '127.0.0.1', /* * CakePHP will use the default DB port based on the driver selected * MySQL on MAMP uses port 8889, MAMP users will want to uncomment * the following line and set the port accordingly */ //'port' => 'non_standard_port_number', 'username' => 'root', 'password' => 'root', 'database' => 'cakephp4', /* * If not using the default 'public' schema with the PostgreSQL driver * set it here. */ //'schema' => 'myapp', /* * You can use a DSN string to set the entire configuration */ 'url' => env('DATABASE_URL', null), ], /* * The test connection is used during the test suite. */ 'test' => [ 'host' => 'localhost', //'port' => 'non_standard_port_number', 'username' => 'my_app', 'password' => 'secret', 'database' => 'test_myapp', //'schema' => 'myapp', 'url' => env('DATABASE_TEST_URL', 'sqlite://127.0.0.1/tests.sqlite'), ], ],
3. Create Model
- Create
Files
Model.
bin/cake bake model Files
- This will create 2 files –
src/Model/Entity/File.php src/Model/Table/FilesTable.php
src/Model/Entity/File.php
If you don’t want to allow insertion and updating of any field then set it to false
.
Completed Code
<?php declare(strict_types=1); namespace App\Model\Entity; use Cake\ORM\Entity; /** * Image Entity * * @property int $id * @property string $filename * @property string $path */ class File extends Entity { protected $_accessible = [ 'filename' => true, 'path' => true, ]; }
src/Model/Table/FilesTable.php
Defined file validation in validationDefault()
method. fileel
is the element name.
Completed Code
<?php declare(strict_types=1); namespace App\Model\Table; use Cake\ORM\Query; use Cake\ORM\RulesChecker; use Cake\ORM\Table; use Cake\Validation\Validator; class FilesTable extends Table { public function initialize(array $config): void { parent::initialize($config); $this->setTable('files'); $this->setDisplayField('id'); $this->setPrimaryKey('id'); } public function validationDefault(Validator $validator): Validator { $validator ->scalar('filename') ->maxLength('filename', 255) ->requirePresence('filename', 'create') ->notEmptyFile('filename'); $validator ->scalar('path') ->maxLength('path', 255) ->requirePresence('path', 'create') ->notEmptyString('path'); // File validation $validator ->notEmptyFile('fileel') ->add('fileel', [ 'mimeType' => [ 'rule' => ['mimeType',['image/jpg','image/png','image/jpeg','application/pdf']], 'message' => 'File type must be .jpg,.jpeg,.png,.pdf', ], 'fileSize' => [ 'rule' => ['fileSize','<', '2MB'], 'message' => 'File size must be less than 2MB', ] ]); return $validator; } }
4. Create Controller
- Create a
FileuploadController.php
file insrc/Controller/
folder. - Create
FileuploadController
Class that extendsAppController
. - Include
App\Model\Entity\File
Entity and to create a new folder includeCake\Filesystem\Folder
. - Create
index()
method –- Create
File
entity instance. - If
<form >
is POST then validate the POST data usingpatchEntity()
. - Read file element details if it is validated.
- If
$error == 0
then assign upload location in$location
variable and check if upload exists or not. If not exists then create it. - Upload the file by calling
moveTo()
. - After upload assign upload path in
$filepath
. - Insert a new record in
files
table. Here, pass$filename
tofilename
and$filepath
topath
. - Fetch all records the
files
table and passfilesList
andfile
to the template.
- Create
NOTE – The uploaded file will be stored in the
webroot/uploads/
folder.
Completed Code
<?php declare(strict_types=1); namespace App\Controller; use App\Model\Entity\File; use Cake\Filesystem\Folder; class FileuploadController extends AppController { public function index(){ ## File entity $file = new File(); $files = $this->getTableLocator()->get('Files'); if ($this->request->is('post')) { // Validate the data $file = $files->patchEntity($file, $this->request->getData()); // File is validated if(!isset($file->getErrors()['fileel'])){ $attachment = $this->request->getData('fileel'); // File details $filename = $attachment->getClientFilename(); $type = $attachment->getClientMediaType(); $size = $attachment->getSize(); $extension = pathinfo($filename, PATHINFO_EXTENSION); $tmpName = $attachment->getStream()->getMetadata('uri'); $error = $attachment->getError(); if($error == 0){ ## Upload location $location = WWW_ROOT . 'uploads' . DS; ## Check upload location exists or not $folder = new Folder(); $checkfolder = $folder->inPath($location, true); if(!$checkfolder){ // Not exists if (!$folder->create($location)) { $this->Flash->error('File not uploaded.'); } } ## Upload file $targetPath = $location.$filename; $attachment->moveTo($targetPath); ## Uploaded file path $filepath = "/uploads/".$filename; ## Insert a record in 'files' table $insData['filename'] = $filename; $insData['path'] = $filepath; $newfile = $files->newEntity($insData); if ($files->save($newfile)) { $this->Flash->success('Inserted successfully.'); }else{ $this->Flash->error('Record not inserted.'); } }else{ $this->Flash->error('File not uploaded.'); } } } // Fetch all records $query = $files->find()->all(); $filesList = $query->toArray(); // Pass to template $this->set('filesList', $filesList); $this->set('file', $file); } }
5. Create Template
Create a new Fileupload
folder in templates/
folder. Now in the Fileupload
folder create index.php
file (templates/Fileupload/index.php)
.
Create a <form >
. Set action
to fileupload/index
. Pass $file
as 1st parameter in create()
. Here, $file
is an entity instance passed from the controller.
Using <table >
to list all stored files in the files
table. Loop on $filesList
Array and check if extension.
If $extension
is an image type then create an image element to display otherwise create a link.
Completed Code
<div class="row"> <div class="col-6"> <?php // Upload form echo $this->Form->create($uploadfile,array('url'=>['controller' => 'fileupload','action' => 'index'],"enctype" => "multipart/form-data" )); echo $this->Form->control('fileel',['label' => 'Select file','type' => 'file','class' => 'form-control','required' => true]); echo $this->Form->button('Submit'); echo $this->Form->end(); ?> <!-- Files list --> <table> <thead> <tr> <th>File</th> <th>Name</th> </tr> </thead> <tbody> <?php foreach ($filesList as $file): ?> <?php $filename = $file['filename']; $path = $file['path']; $extension = pathinfo($filename, PATHINFO_EXTENSION); ?> <tr> <td> <?php $image_exts = array("jpg","jpeg","png"); if(in_array($extension,$image_exts)){ echo $this->HTML->image($path,['width' => '100px']); }else{ echo $this->Html->link( 'View file', $path, ['target' => '_blank'] ); } ?> </td> <td><?= $file['filename'] ?></td> </tr> <?php endforeach; ?> </tbody> </table> </div> </div>
6. Output
7. Conclusion
You have to create a Model and use Entity instance in <form >
creation. Upload the file from the controller on submit and insert a new record in the table.
If you don’t want to save to the database after the file upload then you have to create a Modelless form. I have already written a tutorial this topic which you can view here.
If you found this tutorial helpful then don't forget to share.