Passing objects to Custom Control Structures in Laravel Blade - laravel

I can't call member functions on objects that I pass to custom control structures in Laravel 4.1.23.
My custom control structure:
Blade::extend(function($view, $compiler){
$pattern = $compiler->createMatcher('paginatePretty');
$code =
'$1<?php
echo $2->getCurrentPage();
?>';
return preg_replace($pattern, $code, $view);
});
My blade view code that instantiates paginatePretty:
// $articles = Articles::orderBy('created_at', 'desc')->paginate($per_page);
#paginatePretty($articles)
At compile time, I get this error:
syntax error, unexpected '->' (T_OBJECT_OPERATOR), expecting ',' or ';'
And the custom control structure was compiled like this:
echo ($articles)->getCurrentPage();
How can I pass an object to the custom control structure?

Use list() and array to solve:
Blade::extend(function($view, $compiler){
$pattern = $compiler->createMatcher('paginatePretty');
$code =
'$1<?php
#echo $2->getCurrentPage(); --> the bad code
list($_paginator) = array$2;
echo $_paginator->getCurrentPage();
?>';
return preg_replace($pattern, $code, $view);
});
I prefix variables declared inside of custom control structures with an underscore to avoid collisions in the view.

Related

Simple Dom Parser Returns Empty via Ajax

I'm using Simple HTML Dom Parser to correct some links in my output to good effect but have found some strange behaviour when calling content via Ajax. I'm using the parser on a WordPress site so feed the $content variable into the following function:
function add_trailing_slash( $content ) {
$content = str_get_html( $content );
if( $content ):
foreach( $content->find('a') as $a ):
if( isset( $a->href ) && '' !== $a->href && '#' !== $a->href ):
// replace http with https on all link hrefs
$a->href = str_replace('http:', 'https:', $a->href);
// checks if link lacks trailing slash and appends it if no extension (file)
$ext = pathinfo( $a->href, PATHINFO_EXTENSION );
if( '/' !== substr( $a->href, -1 ) && ! $ext ) $a->href = $a->href . '/';
endif;
endforeach;
endif;
return $content;
}
This is working great when added to the_content filter with add_filter( 'the_content', 'add_trailing_slash' ) and even when called directly like return add_trailing_slash( $output ) however, when I call the same function via Ajax I get a 'success' response but which is completely empty. Stranger still, I found that if I return the output via wpautop( $output ) it comes back just fine. wpautop (link) is essentially a bunch of preg_replace functions to replace double line breaks with <p> tags so I tested returning my output via return preg_replace('<blah>', '', $content) and it worked!
Oh, I also tested removing all my changes from the add_trailing_slash() function above and the same issue persisted so I guess that something to do with the way str_get_html( $content ) parses the input makes it not play well with the Ajax callback. But why does preg_replace make it returnable?
function add_trailing_slash( $content ) {
$content = str_get_html( $content );
return $content;
}
I'm wondering if anyone else has come across this issue, whether I'm missing something and this is expected or whether this is a bug? I could leave in my preg_replace which appears to 'fix' the issue but it feels like something of a hack.
The only thing that come to my mind is that when you do $content = str_get_html( $content ); you are getting an object as result. Maybe when it goes through wp functions it get interpreted like a string but when you are json_encoding it, something may go wrong and kill it. You can either try to force-cast it to string with
return (string) $content;
or try to use
// Dumps the internal DOM tree back into string
$str = $html->save();
as described in the docs

laravel custom blade directive except tag function for htmlentites output

\Blade::directive('specialReplace', function($expression){
$expression = explode(',', $expression);
$exception = $expression[0];
$output = htmlspecialchars($expression[1]);
if ($exception == "img") {
$output = str_replace("<img", "<img", $output);
$output = str_replace("/>", "/>", $output);
} else {
$output = str_replace("<".$exception.">", "<".$exception.">",$output);
$output = str_replace("</".$exception.">", "</".$exception.">",$output);
}
return "<?PHP echo $output?>";
});
#specialReplace(img, <img src=....)
I try to make a custom function for html out image from database without htmlentites in laravel.
My problem is I get an error syntax error, unexpected '&' which I have no idea
anyone know how to fix this?
Try that, it should fix the error
return "<?PHP echo \"$output\"?>";
Also as an argument to your function, given the input
#specialReplace(img, <img src=....)
You'll receive an exact string you passed to the direcive (together with the brackets)
(img, <img src=....)
It doesn't look like you parse it properly.

Laravel 5.2 : Extending Blade by passing an object instead of a string

I want to add some blade directives.
I have in my service provider
Blade::directive('image', function ($media) {
return "<?php echo {$media->getImageUrl()}; ?>";
});
The blade file contain
#image($media)
the $media variable is an object which use the Media model and which contains a public function getImageUrl()which return a string with the url of the image.
When I execute this code, I have this error message
Fatal error: Call to a member function getImageUrl() on string
The object passed in the Blade directive is considered as a string instead of Media object
Is there any way to use $media as an Mediaobject instead of a string ?
The curly braces should be around $media:
Blade::directive('image', function ($media) {
return "<?php echo {$media}->getImageUrl(); ?>";
});
This compiles to:
<?php echo ($media)->getImageUrl(); ?>
As far as I know Blade directives only accept one expression as a string, including the function call braces. So the expression received by the directive is:
"($media)"
After changing directives you should clear the compiled views because Blade is caching the directives, so you would not see your changes taking affect.

Using Blade directives outside of templates

Laravel 5.1: I defined a few custom directives inside a BladeServiceProvider (example below). Now I would like to use them outside of a view template to format strings (I am writing an EXCEL file with PHPExcel in a custom ExportService class). Is it possible to reuse my directives?
Blade::directive('appFormatDate', function($expression) {
return "<?php
if (!is_null($expression)) {
echo date(\Config::get('custom.dateformat'), strtotime($expression));
}
else {
echo '-';
}
?>";
});
The BladeCompiler has a compileString method, which allows you to use the Blade directives outside the views. :)
So, you can do things like this:
$timestamp = '2015-11-10 17:41:53';
$result = Blade::compileString('#appFormatDate($timestamp)');
You can use this:
use Illuminate\Support\Facades\Blade;
$timestamp = '2023-01-28 12:41:53';
Blade::render("#appFormatDate({$timestamp})");

Laravel 4: include template with parameters in single line

I'm trying to save a blade template into a javascript variable but I can't figure out how to remove the line breaks from the template.
I looked at extending blade and created the following code based on BladeCompiler:compileInclude() which removes all line breaks, but only for templates without parameters.
Blade::extend(function($view, $compiler)
{
$pattern = $compiler->createMatcher('include_string');
return preg_replace($pattern, '$1<?php echo str_replace(array("\r","\n"), "", $__env->make($2, array_except(get_defined_vars(), array(\'__data\', \'__path\')))->render()); ?>', $view);
});
I know I could simply remove all line breaks from the template manually but I'm hoping there's a better way.
Has anyone done this before? Any help is appreciated.
I haven't found a way to create your own blade functions that can receive multiple values (or an array) and I don't think it is even possible by using "only" Blade::extend. Of course you could extend Laravel's BladeCompiler class and write much more powerful macros.
But instead I suggest you create a macro for removing the line breaks only.
Blade::extend(function($view, $compiler)
{
$pattern = $compiler->createMatcher('singleline');
return preg_replace($pattern, '$1<?php echo str_replace(array("\r","\n"), "", $2); ?>', $view);
});
And the use it either like this:
#singleline(View::make('view-name', array('foo' => 'bar')))
Or if you prefer the $__env syntax:
#singleline($__env->make('view-name', array('foo' => 'bar')))

Resources