4

I want to create vendor package in cakephp 3. It should depend on another package, that has both php files and some static assets: like js, css, img etc. Setting up php files autoloading I am able to handle. However to load static files from another vendor, e.g.

echo $this->Html->css('AnotherPackage.styles');

cake expects that they should be inside vendor's webroot directory, which they are not

# another package's files
/vendor/author/another-package/php
/vendor/author/another-package/css_files
/vendor/author/another-package/js_files
/vendor/author/another-package/images

Only similar issue I found is copying files to webroot , which is something I do not want to do.

How can I tell cake to load the vendor's files from their exact folders instead of webroot ? Or in what better way this problem can be solved, without being have to copy something. I am using composer.

Thanks

Community
  • 1
  • 1
dav
  • 8,931
  • 15
  • 76
  • 140
  • See my new answer to question you refer https://stackoverflow.com/questions/26736656/loading-javascript-files-from-the-vendors-in-cakephp-3/57496660#57496660 – Yaroslav Aug 14 '19 at 14:28

2 Answers2

0

Are you doing this on a Linux box? If so, you could just create a symbolic link in order to have the webroot directory point right back at the root directory of the package.

QuotidianVoid
  • 609
  • 5
  • 12
0

Are you using composer? Does the project you're working on depend on the vendor's package within your composer.json file? If so, you could create a Controller (something like ExternalAssets) in your project that can read those vendors files, and pass them through to the Response object.

<?php
/**
 * ExternalAssetsController
 */

namespace App\Controller;

use App\Controller\Controller\AppController;
use Cake\Core\App;
use Cake\Http\Exception\BadRequestException;
use Cake\Http\Exception\ForbiddenException;
use Cake\Routing\Router;

/**
 * ExternalAssets Controller
 *
 * Serves up external assets that aren't in the webroot folder.
 */
class ExternalAssetsController extends AppController
{
    /**
     * Initialize method.
     *
     * @return void
     */
    public function initialize()
    {
        parent::initialize();

        $this->loadComponent('RequestHandler');
        // see https://book.cakephp.org/3.0/en/development/routing.html#routing-file-extensions
        // or whatever extensions you need.
        Router::extensions(['css', 'js', 'png', 'jpg']);

        // if you're using the auth component in a restricted way.
        $authAllowedActions = ['asset'];
        $this->Auth->allow($authAllowedActions);
    }

    /**
     * Delivers an asset.
     *
     * @param string|null $folder The Folder's name.
     * @param string|null $file The File's name.
     * @return \Cake\Http\Response
     * @throws \Cake\Http\Exception\BadRequestException When $folder or $file isn't set.
     * @throws \Cake\Http\Exception\ForbiddenException When we can't read the file.
     */
    public function asset($folder = null, $file = null)
    {
        if (!$folder) {
            throw new BadRequestException(__('Folder was not defined'));
        }
        if (!$file) {
            throw new BadRequestException(__('File was not defined'));
        }
        $folder = str_replace('..', '', $folder);
        $file = str_replace('..', '', $file);

        $basepath = realpath(ROOT . DS . 'vendor' . DS . 'author' . DS . 'another-package');
        $path = realpath(ROOT . DS . 'vendor' . DS . 'author' . DS . 'another-package' . DS . $folder . DS . $file . '.' . $this->getRequest()->getParam('_ext'));

        if (strpos($path, $basepath) === false) {
            throw new ForbiddenException(__('Path out of bounds, possible hack attempt.'));
        }

        if (!is_readable($path)) {
            throw new ForbiddenException(__('Unable to read the file.'));
        }

        $this->setResponse($this->getResponse()->withFile($path, [
            'name' => $file . '.' . $this->getRequest()->getParam('_ext'),
            'download' => false
        ]));

        return $this->getResponse();
    }
}

Then use Router::url() to create the compiled path to your controller. Something like:

<link rel="stylesheet" href="<?=Router::url([
    'prefix' => false,
    'plugin' => false, // unless the controller in in a plugin
    'controller' => 'ExternalAssets'
    'action' => 'asset'
    0 => 'css_files',
    1 => 'css_file_name',
    '_ext' => 'css'
]) ?>">
Brian F
  • 1
  • 1