2. How to create downloader in CakePHP3
3. How to create PDF downloader in CakePHP3
At first, we will create a table in the database by a migration file below:
<?php
use Migrations\AbstractMigration;
class CreateCustomers extends AbstractMigration
{
/**
* Change Method.
*
* More information on this method is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-change-method
* @return void
*/
public function change()
{
$table = $this->table('customers');
$table->addColumn('name', 'string', [
'default' => null,
'limit' => 255,
'null' => false,
]);
$table->addColumn('description', 'text', [
'default' => null,
'null' => false,
]);
$table->addColumn('file_location', 'string', [
'default' => null,
'null' => true,
'limit' => 255,
]);
$table->addColumn('created', 'datetime', [
'default' => null,
'null' => false,
]);
$table->addColumn('modified', 'datetime', [
'default' => null,
'null' => false,
]);
$table->create();
}
}
use Migrations\AbstractMigration;
class CreateCustomers extends AbstractMigration
{
/**
* Change Method.
*
* More information on this method is available here:
* http://docs.phinx.org/en/latest/migrations.html#the-change-method
* @return void
*/
public function change()
{
$table = $this->table('customers');
$table->addColumn('name', 'string', [
'default' => null,
'limit' => 255,
'null' => false,
]);
$table->addColumn('description', 'text', [
'default' => null,
'null' => false,
]);
$table->addColumn('file_location', 'string', [
'default' => null,
'null' => true,
'limit' => 255,
]);
$table->addColumn('created', 'datetime', [
'default' => null,
'null' => false,
]);
$table->addColumn('modified', 'datetime', [
'default' => null,
'null' => false,
]);
$table->create();
}
}
Do the following commands for the migrations file:
$ bin/cake migrations migrate
$ bin/cake bake all customers
$ bin/cake bake all customers
Now we will create an uploader with html5.
<input type = "file" name="file"/>
If we use $this->Form->input() in "index.ctp" of CakePHP3:
$this->Form->input('file', ['type'=>'file']);
And we will get an uploader like this:
As a whole, the template page (index.ctp) will be like this:
The code:
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\Customer $customer
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('List Customers'), ['action' => 'index']) ?></li>
</ul>
</nav>
<div class="customers form large-9 medium-8 columns content">
<?= $this->Form->create($customer, ['enctype' => 'multipart/form-data']) ?>
<fieldset>
<legend><?= __('Add Customer') ?></legend>
<?php
echo $this->Form->control('name');
echo $this->Form->control('description');
echo $this->Form->control('file_location', ['type'=>'file']);
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\Customer $customer
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('List Customers'), ['action' => 'index']) ?></li>
</ul>
</nav>
<div class="customers form large-9 medium-8 columns content">
<?= $this->Form->create($customer, ['enctype' => 'multipart/form-data']) ?>
<fieldset>
<legend><?= __('Add Customer') ?></legend>
<?php
echo $this->Form->control('name');
echo $this->Form->control('description');
echo $this->Form->control('file_location', ['type'=>'file']);
?>
</fieldset>
<?= $this->Form->button(__('Submit')) ?>
<?= $this->Form->end() ?>
</div>
Now we have a "controller" of "customers" table because we have used the commad "bake". Open the controller file and edit it to add a "upload" function like this (Please note that you need to add "use Cake\Network\Exception\BadRequestException;" and "use Cake\I18n\Date;" at the top of the file):
private function upload($file, $directory) {
$today = new Date();
$yearmonth = $today->i18nFormat('yyyyMM');
$directory = $directory . "/" . $yearmonth;
if (!file_exists($directory)) {
if (!mkdir($directory, 0755, true)) {
throw new BadRequestException('Impossible de créer le répertoire.');
}
chmod($directory, 0755);
}
switch ($file['error']) {
case 0:
break;
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new BadRequestException('File not found.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new BadRequestException('File is too big.');
default:
throw new BadRequestException('Unknown error');
}
$temp = explode('.', $file["name"]);
$extension = strtolower(end($temp));
$randString = sha1(time() . rand());
$uploadFile = $randString . "." . $extension;
if (!rename($file["tmp_name"], $directory . "/" . $uploadFile)) {
throw new BadRequestException('Impossible to move the file.');
}
return $yearmonth.'/'.$uploadFile;
}
$today = new Date();
$yearmonth = $today->i18nFormat('yyyyMM');
$directory = $directory . "/" . $yearmonth;
if (!file_exists($directory)) {
if (!mkdir($directory, 0755, true)) {
throw new BadRequestException('Impossible de créer le répertoire.');
}
chmod($directory, 0755);
}
switch ($file['error']) {
case 0:
break;
case UPLOAD_ERR_OK:
break;
case UPLOAD_ERR_NO_FILE:
throw new BadRequestException('File not found.');
case UPLOAD_ERR_INI_SIZE:
case UPLOAD_ERR_FORM_SIZE:
throw new BadRequestException('File is too big.');
default:
throw new BadRequestException('Unknown error');
}
$temp = explode('.', $file["name"]);
$extension = strtolower(end($temp));
$randString = sha1(time() . rand());
$uploadFile = $randString . "." . $extension;
if (!rename($file["tmp_name"], $directory . "/" . $uploadFile)) {
throw new BadRequestException('Impossible to move the file.');
}
return $yearmonth.'/'.$uploadFile;
}
And change "add" function too:
public function add()
{
$customer = $this->Customers->newEntity();
if ($this->request->is('post')) {
$data = $this->request->getData();
$data['file_location'] = $this->upload($data['file_location'], WWW_ROOT.'uploads/customers');
$customer = $this->Customers->patchEntity($customer, $data);
if ($this->Customers->save($customer)) {
$this->Flash->success(__('The customer has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The customer could not be saved. Please, try again.'));
}
$this->set(compact('customer'));
$this->set('_serialize', ['customer']);
}
{
$customer = $this->Customers->newEntity();
if ($this->request->is('post')) {
$data = $this->request->getData();
$data['file_location'] = $this->upload($data['file_location'], WWW_ROOT.'uploads/customers');
$customer = $this->Customers->patchEntity($customer, $data);
if ($this->Customers->save($customer)) {
$this->Flash->success(__('The customer has been saved.'));
return $this->redirect(['action' => 'index']);
}
$this->Flash->error(__('The customer could not be saved. Please, try again.'));
}
$this->set(compact('customer'));
$this->set('_serialize', ['customer']);
}
Now you can upload a file from the "add" page.
The uploaded file is in this directory: \cake\webroot\uploads\customers\201712
We can use the uploaded file like this (This example is "index.ctp"):
<?php foreach ($customers as $customer): ?>
<tr>
<td><?= $this->Number->format($customer->id) ?></td>
<td><?= h($customer->name) ?></td>
<td><img src="/cake/uploads/customers/<?= $customer->file_location ?>" width="100" /></td>
<td><?= h($customer->created) ?></td>
<td><?= h($customer->modified) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $customer->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $customer->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $customer->id], ['confirm' => __('Are you sure you want to delete # {0}?', $customer->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
This is the complete code of "index.ctp":
<?php
/**
* @var \App\View\AppView $this
* @var \App\Model\Entity\Customer[]|\Cake\Collection\CollectionInterface $customers
*/
?>
<nav class="large-3 medium-4 columns" id="actions-sidebar">
<ul class="side-nav">
<li class="heading"><?= __('Actions') ?></li>
<li><?= $this->Html->link(__('New Customer'), ['action' => 'add']) ?></li>
</ul>
</nav>
<div class="customers index large-9 medium-8 columns content">
<h3><?= __('Customers') ?></h3>
<table cellpadding="0" cellspacing="0">
<thead>
<tr>
<th scope="col"><?= $this->Paginator->sort('id') ?></th>
<th scope="col"><?= $this->Paginator->sort('name') ?></th>
<th scope="col"><?= $this->Paginator->sort('file_location', 'File') ?></th>
<th scope="col"><?= $this->Paginator->sort('created') ?></th>
<th scope="col"><?= $this->Paginator->sort('modified') ?></th>
<th scope="col" class="actions"><?= __('Actions') ?></th>
</tr>
</thead>
<tbody>
<?php foreach ($customers as $customer): ?>
<tr>
<td><?= $this->Number->format($customer->id) ?></td>
<td><?= h($customer->name) ?></td>
<td><img src="/cake/uploads/customers/<?= $customer->file_location ?>" width="100" /></td>
<td><?= h($customer->created) ?></td>
<td><?= h($customer->modified) ?></td>
<td class="actions">
<?= $this->Html->link(__('View'), ['action' => 'view', $customer->id]) ?>
<?= $this->Html->link(__('Edit'), ['action' => 'edit', $customer->id]) ?>
<?= $this->Form->postLink(__('Delete'), ['action' => 'delete', $customer->id], ['confirm' => __('Are you sure you want to delete # {0}?', $customer->id)]) ?>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
<div class="paginator">
<ul class="pagination">
<?= $this->Paginator->first('<< ' . __('first')) ?>
<?= $this->Paginator->prev('< ' . __('previous')) ?>
<?= $this->Paginator->numbers() ?>
<?= $this->Paginator->next(__('next') . ' >') ?>
<?= $this->Paginator->last(__('last') . ' >>') ?>
</ul>
<p><?= $this->Paginator->counter(['format' => __('Page {{page}} of {{pages}}, showing {{current}} record(s) out of {{count}} total')]) ?></p>
</div>
</div>