CakePHP 3.5 and spout/xlsx library : how to handle .xlsx extension


I installed the spout php library for handling xlsx files. see

So far I am calling a method in my controller like:

I would prefer to ask for:

and manage a dedicated controller for handling my xlsx files.
How can I do that?

I started by adding in my routes.php :

But this is not enough.
Thank you for you kind attention


Hi Kitcat711! :wink:

In your routes.php

use Cake\Core\Plugin;
use Cake\Routing\RouteBuilder;
use Cake\Routing\Router;
use Cake\Routing\Route\DashedRoute;


Router::scope('/', function (RouteBuilder $routes) {
    $routes->connect('/', ['controller' => 'Pages', 'action' => 'display', 'home']);
    $routes->connect('/pages/*', ['controller' => 'Pages', 'action' => 'display']);
    $routes->connect('/articles/:id', [
        'controller' => 'Articles',
        'action' => 'xlsx'


In your ArticlesController.php

namespace App\Controller;

use App\Controller\AppController;
use Cake\Utility\Hash;
use Box\Spout\Writer\WriterFactory;
use Box\Spout\Common\Type;

class ArticlesController extends AppController
    public function xlsx($id = null)
        $query = $this->Articles->find();
        $query->formatResults(function ($results) {
            return $results->map(function ($row) {
                if (isset($row['created'])) {
                    $row['created'] = $row['created']->i18nFormat('dd/MM/yyyy HH:mm:ss', 'Europe/Paris');
                return $row;
        $items = $query->enableHydration(false)->toArray();
        if (!$items) {
            $this->Flash->error('Nothing to export');
        $rows = [];
        foreach($items as $item) {
            $rows[] = Hash::flatten($item);
        $headers = array_keys($rows[0]);
        $writer = WriterFactory::create(Type::XLSX);
        $target = TMP . $id . '.xlsx';

        $response = $this->response->withFile($target, ['download' => true]);
        return $response;

Anywhere in your template

echo $this->Html->link('Export Articles', [
    'controller' => 'Articles', 'action' => 'xlsx', 1, '_ext' => 'xlsx'

Will try that Guillaume, and let you know :slight_smile: