Symfony 4 route to assets folder - php

I am trying to load the stylesheet in my Assets folder following the instruction giving on this page:
https://symfony.com/doc/current/best_practices/web-assets.html
But I fail to navigate from the base.html.twig to the folder using:
<link rel="stylesheet" type="text/css" href="/assets/css/style.css" />
my file structure looks like this:
templates
base.html.twig
assets
css
style.css
Any ideas why this doesn't work?

You can try to use symfony's asset function:
<link rel="stylesheet" href="{{ asset('css/style.css') }}" />

In your AppExtension:
// register function here
public function getFunctions() {
return [
new TwigFunction('load_js_asset', array($this, 'fileGetJsAsset')),
];
}
// register filter here
public function getFilters() : array
{
return [
new TwigFilter('html_entity_decode',
[$this, 'html_entity_decode'],
['is_safe' => ['html']]),
}
/**
* #param string $string
* #return string
*/
public function html_entity_decode(string $string) : string {
return html_entity_decode($string);
}
/**
* #param string $file
* #param bool $embedScriptTag
* #return string
*/
public function fileGetJsAsset(string $file, bool $embedScriptTag = true) : string {
/** #var bool|string $content */
$content = file_get_contents(__DIR__ . '/../../assets/js/' . $file);
if ($content === false) {
throw new FileException('Could not found or read file: ' . $file);
}
if (!$embedScriptTag) {
return $content;
}
return '<script>' . $content . '</script>';
}
Now in your view load js assets like this:
// loading from root assets/js folder
{{ load_js_asset('core/jquery.min.js', true)|html_entity_decode }}
{{ load_js_asset('core/popper.min.js')|html_entity_decode }}
{{ load_js_asset('my-beauty-js-file.js')|html_entity_decode }}`
I hope it helps.
Maybe you will need also htmlspecialchars_decode filter.

http://symfony.com/doc/3.4/best_practices/web-assets.html
Assets function still being usefull in Symfony 4.

A couple of possible solutions - without more detail I can't be sure if they will definitely solve the problem or not:
First, did you configure webpack-encore and run the build? Without that the resources won't be there and nginx will generate a 404 trying to route to it.
Second, if you're running with Docker, you may not have mounted the ./app/public/ folder onto the nginx container so that the files could be served. If you are getting a Symfony 404 when you go to those files, this may be the issue.

Related

Access and load a PDF from Storage into Browser in Laravel

I am trying to access and load a PDF in the browser using Laravel for the first time. Not sure what I am doing wrong.
I have the following route in my web.php:
use Illuminate\Http\Response;
Route::get('public/downloads/{pathToFile}', function ($pathToFile) {
return response()->file($pathToFile);
});
I have the following in my view:
<a class='col-6' href="/downloads/{{ asset('public/storage/'
. $plansubmission->current_plan_year_claims_data_file_1) }}">{{
asset('storage/' . $plansubmission-
>current_plan_year_claims_data_file_1) }}</a>
From the docs: The public disk is intended for files that are going to be publicly accessible. By default, the public disk uses the local driver and stores these files in storage/app/public.
This is assuming you have created a symbolic link by running php artisan storage:link. Otherwise, you might need to tweak this for wherever you are storing the PDF, but I think this approach accomplishes what you're after.
Routes/web.php
Route::get('/public/download/{filename}', 'PdfController#download')->name('download.pdf');
PdfController
use Illuminate\Support\Facades\Storage;
/**
* Display a PDF directly in the browser
*
* #param $filename <-- the filename we want
*
* #return Response
**/
public function download($filename)
{
$url = $filename.'.pdf';
if( $this->storageObjectExists('public', $url) == true ) // Does this file exist?
{
return response()->file($url); // <-- display file directly in browser
} else {
return back()->with('danger', 'No file located!'); // Let the user know
}
}
/**
* Determine if a particular file exists on a disk
*
* #param $disk <-- 'local', 'azure', 'aws', etc
* #param $url <-- /path/to/file.pdf
*
* #return boolean
**/
public function storageObjectExists($disk, $url)
{
$exists = Storage::disk($disk)->exists($url);
return $exists;
}
Form.blade.php
<!-- optional warning for user -->
#if(session('danger'))
<div class="alert alert-danger">
<p>{{ session('danger') }}</p>
</div>
#endif
{{ $filename }}

Setting scripts/rel in head tag of html layout in blade template

I started a new laravel application, and currently working on the main html template layout, I faced a issue.
I made a helper class that could set "version", so I can refresh the cache when I have new release.
namespace App\Http\Helpers;
class HTML
{
private const VERSION = '20180515';
private static function setVersion(&$file): void
{
$file = $file . '?v=' . self::VERSION;
}
public static function style(string $file): string
{
self::setVersion($file);
return '<link rel="stylesheet" type="text/css" href="' . $file . '">';
}
public static function script(string $file): string
{
self::setVersion($file);
return '<script src="' . $file . '"></script>';
}
}
And in the layout I use this:
...
<head>
...
{{ \App\Http\Helpers\HTML::style('css/layout.css') }}
</head>
Is there a way to use the HTML helper class so I don't have to call the namespaces every time?
Include in config/app.php
...
'aliases' => [
....
'HTML' => \App\Http\Helpers\HTML::class,
],
HTML is a common word and you may have some issues. If you have, use a differente key.
Anyway, you can then use
{!! HTML::style('css/layout.css') !!}
Also, if you have any issue, run
php artisan config:clear

Lumen : How to display the image on a public folder?

I want to display the image that stored in public folder on Lumen project.
But I got 404 not found when try to display it in browser.
I already create the asset url helper:
if (!function_exists('urlGenerator')) {
/**
* #return \Laravel\Lumen\Routing\UrlGenerator
*/
function urlGenerator() {
return new \Laravel\Lumen\Routing\UrlGenerator(app());
}
}
if (!function_exists('asset')) {
/**
* #param $path
* #param bool $secured
*
* #return string
*/
function asset($path, $secured = false) {
return urlGenerator()->asset($path, $secured);
}
}
and this is how I call the image URL :
asset('public/uploads/images/product/') . $product->image
why lumen referring to route when I try to call image in public folder ?
You can do like the below.
asset('uploads/images/product/' . $product->image)
or
asset('uploads/images/product/') . '/' . $product->image
The asset() URL helper already generates a path to your root folder (which is inside the public fodler) and so you don't need to include it.
Using:
asset('uploads/images/product/' . $product->image)
or
asset('uploads/images/product/') . $product->image
should work just fine for you.
Remember you can always look at the link that gets generated to see what your helper is generating - and tweak it as required.

How to override bundle resources in micro-kernel Symfony?

I've got micro-kernel Symfony project with custom catalog structure.
I used this: https://github.com/ikoene/symfony-micro
How can I override e.g. Twig Resources (Exception views)?
Cookbook says that I should create a directory called TwigBundle in my Resources directory.
I made \AppBundle\Resources\TwigBundle\views\Exception directory. Overriding view does not seem to work.
Thanks for using the microkernel setup. Here's how to override exception views.
1. Create a custom ExceptionController
First off, we're gonna create our own ExceptionController which extends the base ExceptionController. This will allow us to overwrite the template path.
<?php
namespace AppBundle\Controller\Exception;
use Symfony\Bundle\TwigBundle\Controller\ExceptionController as BaseExceptionController;
use Symfony\Component\HttpFoundation\Request;
class ExceptionController extends BaseExceptionController
{
/**
* #param Request $request
* #param string $format
* #param int $code
* #param bool $showException
*
* #return string
*/
protected function findTemplate(Request $request, $format, $code, $showException)
{
$name = $showException ? 'exception' : 'error';
if ($showException && 'html' == $format) {
$name = 'exception_full';
}
// For error pages, try to find a template for the specific HTTP status code and format
if (!$showException) {
$template = sprintf('AppBundle:Exception:%s%s.%s.twig', $name, $code, $format);
if ($this->templateExists($template)) {
return $template;
}
}
// try to find a template for the given format
$template = sprintf('#Twig/Exception/%s.%s.twig', $name, $format);
if ($this->templateExists($template)) {
return $template;
}
// default to a generic HTML exception
$request->setRequestFormat('html');
return sprintf('#Twig/Exception/%s.html.twig', $showException ? 'exception_full' : $name);
}
}
2. Create the error templates
Create templates for the different error codes:
error.html.twig
error403.html.twig
error404.html.twig
In this example, the exception templates would be placed in AppBundle/Resources/views/Exception/
3. Override the default ExceptionController
Now let's point to our new exception controller in the configuration.
twig:
exception_controller: app.exception_controller:showAction
I really like your solution, but I found another way how to do it without custom exception controller.
I realized that automatical additional check for overrided templates happens in directory Resources in the directory when you store your kernel class.
So, for structure in your repo it's:
/Resources/TwigBundle/views/Exception/
Finally I changed a little bit the directory structure to have a 'app' directory with kernel file inside. Just like in the default Symfony project.

Is there any way to compile a blade template from a string?

How can I compile a blade template from a string rather than a view file, like the code below:
<?php
$string = '<h2>{{ $name }}</h2>';
echo Blade::compile($string, array('name' => 'John Doe'));
?>
http://paste.laravel.com/ujL
I found the solution by extending BladeCompiler.
<?php namespace Laravel\Enhanced;
use Illuminate\View\Compilers\BladeCompiler as LaravelBladeCompiler;
class BladeCompiler extends LaravelBladeCompiler {
/**
* Compile blade template with passing arguments.
*
* #param string $value HTML-code including blade
* #param array $args Array of values used in blade
* #return string
*/
public function compileWiths($value, array $args = array())
{
$generated = parent::compileString($value);
ob_start() and extract($args, EXTR_SKIP);
// We'll include the view contents for parsing within a catcher
// so we can avoid any WSOD errors. If an exception occurs we
// will throw it out to the exception handler.
try
{
eval('?>'.$generated);
}
// If we caught an exception, we'll silently flush the output
// buffer so that no partially rendered views get thrown out
// to the client and confuse the user with junk.
catch (\Exception $e)
{
ob_get_clean(); throw $e;
}
$content = ob_get_clean();
return $content;
}
}
Small modification to the above script.
You can use this function inside any class without extending the BladeCompiler class.
public function bladeCompile($value, array $args = array())
{
$generated = \Blade::compileString($value);
ob_start() and extract($args, EXTR_SKIP);
// We'll include the view contents for parsing within a catcher
// so we can avoid any WSOD errors. If an exception occurs we
// will throw it out to the exception handler.
try
{
eval('?>'.$generated);
}
// If we caught an exception, we'll silently flush the output
// buffer so that no partially rendered views get thrown out
// to the client and confuse the user with junk.
catch (\Exception $e)
{
ob_get_clean(); throw $e;
}
$content = ob_get_clean();
return $content;
}
For anyone still interested in this, they've added it to Laravel 9
use Illuminate\Support\Facades\Blade;
return Blade::render('Hello, {{ $name }}', ['name' => 'Julian Bashir']);
https://laravel.com/docs/9.x/blade#rendering-inline-blade-templates
I just stumbled upon the same requirement! For me, i had to fetch a blade template stored in DB & render it to send email notifications.
I did this in laravel 5.8 by kind-of Extending \Illuminate\View\View. So, basically i created the below class & named him StringBlade (I couldn't find a better name atm :/)
<?php
namespace App\Central\Libraries\Blade;
use Illuminate\Filesystem\Filesystem;
class StringBlade implements StringBladeContract
{
/**
* #var Filesystem
*/
protected $file;
/**
* #var \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
protected $viewer;
/**
* StringBlade constructor.
*
* #param Filesystem $file
*/
public function __construct(Filesystem $file)
{
$this->file = $file;
$this->viewer = view();
}
/**
* Get Blade File path.
*
* #param $bladeString
* #return bool|string
*/
protected function getBlade($bladeString)
{
$bladePath = $this->generateBladePath();
$content = \Blade::compileString($bladeString);
return $this->file->put($bladePath, $content)
? $bladePath
: false;
}
/**
* Get the rendered HTML.
*
* #param $bladeString
* #param array $data
* #return bool|string
*/
public function render($bladeString, $data = [])
{
// Put the php version of blade String to *.php temp file & returns the temp file path
$bladePath = $this->getBlade($bladeString);
if (!$bladePath) {
return false;
}
// Render the php temp file & return the HTML content
$content = $this->viewer->file($bladePath, $data)->render();
// Delete the php temp file.
$this->file->delete($bladePath);
return $content;
}
/**
* Generate a blade file path.
*
* #return string
*/
protected function generateBladePath()
{
$cachePath = rtrim(config('cache.stores.file.path'), '/');
$tempFileName = sha1('string-blade' . microtime());
$directory = "{$cachePath}/string-blades";
if (!is_dir($directory)) {
mkdir($directory, 0777);
}
return "{$directory}/{$tempFileName}.php";
}
}
As you can already see from the above, below are the steps followed:
First converted the blade string to the php equivalent using \Blade::compileString($bladeString).
Now we have to store it to a physical file. For this storage, the frameworks cache directory is used - storage/framework/cache/data/string-blades/
Now we can ask \Illuminate\View\Factory native method 'file()' to compile & render this file.
Delete the temp file immediately (In my case i didn't need to keep the php equivalent file, Probably same for you too)
And Finally i created a facade in a composer auto-loaded file for easy usage like below:
<?php
if (! function_exists('string_blade')) {
/**
* Get StringBlade Instance or returns the HTML after rendering the blade string with the given data.
*
* #param string $html
* #param array $data
* #return StringBladeContract|bool|string
*/
function string_blade(string $html, $data = [])
{
return !empty($html)
? app(StringBladeContract::class)->render($html, $data)
: app(StringBladeContract::class);
}
}
Now i can call it from anywhere like below:
<?php
$html = string_blade('<span>My Name is {{ $name }}</span>', ['name' => 'Nikhil']);
// Outputs HTML
// <span>My Name is Nikhil</span>
Hope this helps someone or at-least maybe inspires someone to re-write in a better way.
Cheers!
I'm not using blade this way but I thought that the compile method accepts only a view as argument.
Maybe you're looking for:
Blade::compileString()
It's a old question. But I found a package which makes the job easier.
Laravel Blade String Compiler renders the blade templates from the string value. Check the documentation on how to install the package.
Here is an example:
$template = '<h1>{{ $name }}</h1>'; // string blade template
return view (['template' => $template], ['name' => 'John Doe']);
Note: The package is now updated to support till Laravel 6.
I know its pretty old thread, but today also requirement is same.
Following is the way I solved this on my Laravel 5.7 (but this will work with any laravel version greater than version 5), I used the knowledge gained from this thread and few other threads to get this working (will leave links to all threads at the end, if this help up-vote those too)
I added this to my helper.php (I used this technique to add helper to my project, but you can use this function directly as well)
if (! function_exists('inline_view')) {
/**
* Get the evaluated view contents for the given blade string.
*
* #param string $view
* #param array $data
* #param array $mergeData
* #return \Illuminate\View\View|\Illuminate\Contracts\View\Factory
*/
function inline_view($view = null, $data = [], $mergeData = [])
{
/* Create a file with name as hash of the passed string */
$filename = hash('sha1', $view);
/* Putting it in storage/framework/views so that these files get cleared on `php artisan view:clear*/
$file_location = storage_path('framework/views/');
$filepath = storage_path('framework/views/'.$filename.'.blade.php');
/* Create file only if it doesn't exist */
if (!file_exists($filepath)) {
file_put_contents($filepath, $view);
}
/* Add storage/framework/views as a location from where view files can be picked, used in make function below */
view()->addLocation($file_location);
/* call the usual view helper to render the blade file created above */
return view($filename, $data, $mergeData);
}
}
Usage is exactly same as laravel's view() helper, only that now first parameter is the blade string
$view_string = '#if(strlen($name_html)>6)
<strong>{{ $name_html }}</strong>
#else
{{$name_html}}
#endif';
return inline_view($view_string)->with('name_html', $user->name);
return inline_view($view_string, ['name_html' => $user->name]);
References:
https://stackoverflow.com/a/31435824/4249775
https://stackoverflow.com/a/33594452/4249775
Laravel 9 :
use Illuminate\Support\Facades\Blade;
return Blade::render('Your Blade Content {{ $parameter1}}', ['parameter1' => 'Name']);

Categories