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

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.

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 }}

Symfony 4 route to assets folder

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.

Laravel in a subfolder and pagination

I've my Laravel project in a sub (sub) folder from my root folder and am using the simplePaginate() method in some views. After a little search I've noticted the AbstractPaginator is used and provides a method url() which is somewhere down the road invoked by the BootstrapThreeNextPreviousButtonRendererTrait which gets called from SimpleBootstrapThreePresenter.
I've been searching in the my config/app.php and helpers.php file to find something pointing to a solution. But haven't found anything yet.
How can I set up Laravel (5.1) to use my subfolder structure with the pagination class?
I've solved it modifying the BootstrapThreeNextPreviousButtonRendererTrait. I'm aware I could have also modified the AbstractPaginator but since I'm not overseeing the consequences of that right now I've chosen to tailor the trait to my needs, like so:
<?php
namespace Illuminate\Pagination;
use Illuminate\Support\Facades\Request;
trait BootstrapThreeNextPreviousButtonRendererTrait
{
/**
* Get the previous page pagination element.
*
* #param string $text
* #return string
*/
public function getPreviousButton($text = '«')
{
// If the current page is less than or equal to one, it means we can't go any
// further back in the pages, so we will render a disabled previous button
// when that is the case. Otherwise, we will give it an active "status".
if ($this->paginator->currentPage() <= 1) {
return $this->getDisabledTextWrapper($text);
}
$url = url() . '/' . Request::path() . '?page=' . ($this->paginator->currentPage() - 1);
//Laravel shipped code disabled because of an installation in a sub-sub folder.
//$url = $this->paginator->url(
// $this->paginator->currentPage() - 1
//);
return $this->getPageLinkWrapper($url, $text, 'prev');
}
/**
* Get the next page pagination element.
*
* #param string $text
* #return string
*/
public function getNextButton($text = '»')
{
// If the current page is greater than or equal to the last page, it means we
// can't go any further into the pages, as we're already on this last page
// that is available, so we will make it the "next" link style disabled.
if (! $this->paginator->hasMorePages()) {
return $this->getDisabledTextWrapper($text);
}
$url = url() . '/' . Request::path() . '?page=' . ($this->paginator->currentPage() + 1);
//Laravel shipped code disabled because of an installation in a sub-sub folder.
//$url = $this->paginator->url($this->paginator->currentPage() + 1);
return $this->getPageLinkWrapper($url, $text, 'next');
}
}

Symfony remove cached images using liipImagine

I'm trying to remove cached images (which are created with LiipImagineBundle) when the source image is deleted or updated. I have already found out that it could be done using CacheManager ( https://github.com/liip/LiipImagineBundle/issues/132 )
The problem is that I can't figure it out how to use it exactly. What else do I need to add (like libraries) to my code despite these three lines:
$cacheManager = $this->get('liip_imagine.cache.manager');
$cacheManager->resolve($this->getRequest(),$pngPath,$filter);
$cacheManager->remove($pngPath, $filter);
I believe there should be something like
$cacheManager = new CacheManager();
I would really appreciate if anyone could explain me how to do that in more detail.
So, for example in your controller:
/**
* Remove an image in the cache based on its relative path and the filter applied to it
*
* #param string $path
* #param string $filter
*
* #return void
*/
protected function removeCachedImageAction($path, $filter)
{
$cacheManager = $this->container->get('liip_imagine.cache.manager');
// Remove the cached image corresponding to that path & filter, if it is stored
if ($cacheManager->isStored($path, $filter)) {
$cacheManager->remove($path, $filter);
}
}
/**
* An action that doesn't do much except testing the function above
*
* #param Request $request
*
* #return void
*/
protected function whateverAction(Request $request)
{
$path = //... probably from the request
$filter = //... probably from the request
// Remove the cached image
$this->removeCachedImage($path, $filter);
// ...
}
As you can see in the CacheManager, the function that you'd like to use is:
public function remove($paths = null, $filters = null){ ... }
If $paths is null, the function assumes that you want to remove the cached images for ALL PATHS that have been resolved with the $filters provided.
If $filters is null, the function assumes that you want to remove the cached images corresponding for the $paths provided and that have previously been resolved with ALL FILTERS.
If $paths and $filters are null, the function assumes that you want to remove the cached images corresponding to ALL PATHS and for ALL FILTERS. Basically ALL CACHED IMAGES.

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