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'
]) ?>">