Getting error when using {{ Str::limit }} helper class in Laravel Blade - php

I'm building an app using Laravel 6.5, upgraded from Laravel 5.7.
I have a field that pulls text from the DB and displays the first 50 characters, using the Blade syntax:
...
{{ Str::limit($someValue->value, 50) }} // This worked
...
{{ Str::limit($someOtherValue->value, 50) }} // This gave error message
...
and when accessing the page I get
ErrorException (E_ERROR)
Class 'Str' not found
The original code uses the helper class str_limit() which was deprecated since Laravel 5.8.
So when I took over this project and upgraded Laravel, I updated the code to the above.
From my understanding, Str::limit() is a global helper class and should work without having to declare any Facade or add aliases. The fact that the above code worked partially proves it.
I implemented a working fix:
...
{{ Str::limit($someValue->value, 50) }} // This worked
...
{{ \Illuminate\Support\Str::limit($someOtherValue->value, 50) }} // This now works
...
Although I have a working fix, the ugliness of the code hurts my eyes and it drives me nuts not know WHY only 1 of it worked?? My linter and bracket highlighting tell me there are no missing tags. I've also copied the same code and applied in every combination, it's just that second Str::limit() which is not working.
Can anyone tell me why it's behaving this way? Thank you!

I suggest you to use Mutator. It's a good way when you modify your data from your database. Don't make your blade file messy.
******* Model ********
use Illuminate\Support\Str;
public function getSomeFieldAttribute($value)
{
return str_limit($value, 50);
}
Note: someField is a column that you want to limit.

In controller you can use code like below
use Illuminate\Support\Str;
then
Example :-
$limit_string = Str::limit('This is just an example', 5);
In View file if you want to use then
{{\Illuminate\Support\Str::limit('This is just an example',5)}}
you can't extend facade to blade file . if you want to use str then you have define a path and use that helper function that is limit here .
arr and str is global function but in laravel 5.8 they deprecated this functionality so if you want to use this str or arr helpers then you have to use
Illuminate\Support\Str (str) and use Illuminate\Support\Arr (arr) to perform operation.

Ok I figured out my problem.
...
if (someCondition not fulfilled) {
{{ Str::limit($someValue->value, 50) }} // This actually didn't work but got skipped
} else {
'Some error message' // THIS worked
...
if (someCondition fulfilled) {
{{ Str::limit($someOtherValue->value, 50) }} // This gave error message
} else {
'Some error message' // Skipped
...
The Str helper function only worked after declaring an alias for Str in config/app.php and clearing the cache: php artisan view:clear & php artisan config:clear
'aliases' => [
'App' => Illuminate\Support\Facades\App::class,
'Artisan' => Illuminate\Support\Facades\Artisan::class,
'Auth' => Illuminate\Support\Facades\Auth::class,
'Blade' => Illuminate\Support\Facades\Blade::class,
...
'Str' => Illuminate\Support\Str::class
]
Much thanks to everyone who offered help here!

Related

Laravel Blade component method undefined in production but work in local dev

I have a component NoteTag in app/View/Components/Notes and the blade component in resources/views/components/notes.
I am using this component in a parent component like this:
<x-notes.note-tag :name="$tag->name"></x-notes.note-tag>
NoteTag has a method which I want to use in the view:
public function typeColor()
{
return substr(md5($this->name), 0, 6);
}
I reference the method in the view like this:
<span style="border: 2px #{{ $typeColor() }} solid" class="rounded-lg mr-2 px-1 bg-gray-200 text-gray-600 shadow">
{{ $name }}
</span>
This works great in local development, but in production i get this:
[previous exception] [object] (ErrorException(code: 0): Undefined variable $typeColor at /home/forge/loggbok.michaelsimsoe.no/storage/framework/views/e354b32f864ce675974b798281d94fe7f4dd2831.php:1)
[stacktrace]
I've also tried to pass it to the view as data:
public function render()
{
return view('components.notes.note-tag', ['color' => $this->typeColor()]);
}
Which results in the same error. So I guess there is some mapping issue in production where the component view cant fin the class.
As per https://github.com/laravel/framework/issues/31919 and Laravel docs: Manually Registering Components I've tried this in the AppServiceProvider:
use App\View\Components\Notes\NoteTag;
use Illuminate\Support\Facades\Blade;
...
class AppServiceProvider extends ServiceProvider
{
...
public function boot()
{
Blade::component('note-tag', NoteTag::class);
}
...
With no luck.
I've seen multiple mentions of this problem:
SO: laravel 7 blade component public methods not working
SO: Laravel Components not getting my methods in shared host
Laracasts.com: laravel 7 blade component public methods not working
Some mention the casing of the class name as an issue. Some mention the manually registering of components. None of them works for me.
I'm using Forge to host the app on DigitalOcean.
I'm using the latest version of Laravel and PHP 8.
The repo for the application
Any ideas?
Converting my comment to an answer, because who doesn't love reputation?! ;)
First things first, have you deleted all files in storage/framework/views on the production server?
I'd wager that the issue is just a caching one, so php artisan view:clear or manually deleting the files in that folder will almost certainly solve this (famous last words)!
Aside from that, is there a reason that app/Views/Components/Notes/NoteTag.php has a class name of noteTag (with a lowercase n)?
Try changing that to see if that resolves the issue.
Laravel is very particular with it's naming schemes.
All file names must match their namespace and class names perfectly, this includes casing. This is not the case for views, they can be located anywhere, since they are called in render method with the relative paths.
the only solution worked for me was to move my components to App\View\Components folder like
php artisan make:component notetag

Extending blade with a service

I installed graham-campbell/markdown, and it works in the controller. I would like to extend it's functionality to blade so I could use #markdown($variable) but can't figure out how to accomplish that.
This is how my AppServiceProvider's boot method looks like with the added blade directive.
public function boot()
{
Schema::defaultStringLength(191);
Blade::directive('markdown', function ($expression) {
return "<?php echo Markdown::convertToHtml($expression); ?>";
});
}
And in my view
#markdown($comment->comment)
But I"m getting the following error:
Class 'Markdown' not found (View: C:\xampp\htdocs\portfolio\portfolio\resources\views\blog.blade.php)
I've added the use at the top of AppServiceProvider file:
use GrahamCampbell\Markdown\Facades\Markdown;
And still the same error. I've even tried the following directive instead of the one I have posted previously:
Blade::directive('markdown', function ($expression) {
return Markdown::convertToHtml($expression);
});
And although it's frowned upon, I've tried to inject the markdown class into the view
#inject('markdown', 'GrahamCampbell\Markdown\Facades\Markdown')
The error no longer shows, but it simply displays $comment->comment.
If I put #markdown(foo **this**) I get 'foo this' just like I would expect. How do I extract the contents of '$comment->comment' and submit it to be parsed by the markdown compiler?
Also, is it possible to do that without the Facades injection?
[EDIT]
I've solved my issue where it just prints $comment->comment. I've removed any changes to AppServiceProvider... I've removed that use statement and blade directive and just using the following in view
#inject('markdown', 'GrahamCampbell\Markdown\Facades\Markdown')
{!! $markdown::convertToHtml($comment->comment) !!}
But I'm still interesting in using the directive #markdown($variable) without the need for that injection.
The first line of code is correct except that you need to add {} instead of (), please refer to this answer.
so you need to type it like this:{$expression} instead of ($expression).
here as well a good tutorial on how to create a custom directive and you can check laracasts.

how to highlight string in a string in a laravel blade view

Somewhere in my template I have this:
{{ $result->someText }}
Now in this text I want to highlight all words that are in the string
{{ $searchString }}
So I thought I create a new blade directive:
{{ #highlightSearch($result->someText, $searchString) }}
Blade::directive('highlightSearch', function($input, $searchString)...
error: missing argument 2
Found out that directives do not except 2 arguments. I tried every workaround that I could find but none worked. They always return the arguments as a plain string, not even passing the actual values.
I tried adding a helper function like explained here: https://stackoverflow.com/a/32430258/928666. Did not work:
error: unknown function "highlightSearch"
So how do I do this super easy task in laravel? I don't care about the highlighting function, that's almost a one-liner.
The reality is blade directives can't do what you need them to do. Whether or not they should is not a topic I can't help with. However you can instead do this in your service provider:
use Illuminate\Support\Str;
/* ... */
Str::macro('highlightSearch', function ($input, $searchString) {
return str_replace($searchString, "<mark>$searchString</mark>", $input);
//Or whatever else you do
});
Then in blade you can just do:
{!! \Illuminate\Support\Str::highlightSearch($result->someText, $searchString) !!}
I've just tested in Laravel 5.1 it and it works without any problem:
\Blade::directive('highlightSearch', function($input) {
return "<?php echo strtoupper($input); ?>";
});
in boot method of AppServiceProvider
and in view I can use:
#highlightSearch('test')
and it returns TEST as expected.
Make sure you are using Blade from global namespace, also run
php artisan clear-compiled
to make sure everything is refreshed. If it won't help, you can try running
composer dump-autoload
just in case.
EDIT
I've also tested it with additional argument and it really seems not be working as expected, so the most reasonable would be adding helper file (if you don't have any with simple PHP function) as for example:
function highlight_search($text, $searchString)
{
// return whatever you want
}
and later use it it in Blade as any other function like so:
{{ highlight_search('Sample', 'Sam') }}
optionally using
{!! highlight_search('Sample', 'Sam') !!}
if you want highlight_search to output HTML

symfony - call a controller-action within a twig extention

I'm trying to call a controller from a twig extention.
I do not want to call the controller as a service since I'd lose all the fancy shortcuts.
Want I want to achieve is to call the controller like twig do it when you do :
{{ render(controller(
'AppBundle:Article:recentArticles',
{ 'max': 3 }
)) }}
I looked at the sourcecode of the "render" and tried to find the "controller" twig's functions, but I did not managed to understand how to do.
From now I achieved an unsatisfying but functionnal code :
In my twig extention :
return $environment->render('FooBundle:TwigExtension/CmsExtension:cmsRenderHook.html.twig', [
'hook' => $hook,
]);
In the CmsExtension:cmsRenderHook.html.twig template :
{{ render(controller(hook.stringControllerAction, hook.arrayParameters)) }}
I think (maybe wrongly) that it would be faster to call it without the template step.
EDIT : I finally successed to code this :
$environment->getExtension('Symfony\Bridge\Twig\Extension\HttpKernelExtension')->renderFragment(
$environment->getExtension('Symfony\Bridge\Twig\Extension\HttpKernelExtension')->controller(
$hook['action'],
$hook['jsonParameters']
)
);
(I did a grep in twig's cache and reproduced it compiled version).
my only concern is about referring to Symfony\Bridge\Twig\Extension\HttpKernelExtension, i'd rather let twig handle this choice, but I can't find out how.
I have two questions:
- do you think that Symfony\Bridge\Twig\Extension\HttpKernelExtension is stable enought to refere explicitly to it?
- if not how would you do to let twig handle it?
You could also get the Twig_SimpleFunction from the Twig_Environment:
$renderFunction = $environment->getFunction('render'); // get the env via initRuntime(..) in your extension
$callable = $renderFunction->getCallable();
However, I would not recommend relying on Twig internals. You should probably extract the functionality into a service.

Laravel 5: Class 'HTML' not found

I'm just getting started with Laravel. I'm in a controller method and I say:
return \View::make('scrape', $data);
Then in scrape.blade.php I have:
#extends('layouts.master');
Finally, in layouts/master.blade.php I have:
{{ HTML::style('css/bootstrap.min.css') }}
And that where things seem to fall apart and I get:
FatalErrorException in 002eb18bb71fd3ec1de058967b799d49 line 6:
Class 'HTML' not found
What am I doing wrong? Thanks for your help.
Searching on google I found this
"By default in Laravel 5.0, Html and Form are not embedded anymore."
You need to add this package to you application.
Please use above links and last change HTML to Html.
eg:
{{ HTML::style('css/bootstrap.min.css') }}
to
{{ Html::style('css/bootstrap.min.css') }}.
its working.

Categories