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']);
Related
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.
I have set of class that send mails to my coworkers, while specific event happens. I had no problem with this so far, until today. I have to run some code from CLI (target - cron) to send daily reports. As you might suspect - no controller nor view is involved.
My code:
/**
* Returns mail content
*
* #param Crm_Mail_Abstract_AlertMail $object
* #return string
* #throws Exception
*/
private function generateContent(Crm_Mail_Abstract_AlertMail $object)
{
$subContent = $object->getInnerContent();
if (!$subContent) {
throw new Exception('Cannot load subcontent');
}
$view = Zend_Layout::getMvcInstance()->getView();
$content = $view->partial($this->mainLayout, array('content' => $subContent));
return $content;
}
And the error I get:
PHP Fatal error: Call to a member function getView() on a non-object
in /home/..../library/Crm/Mail/AlertMail.php on line 195
So... how to render partials while in terminal?
According to This : http://framework.zend.com/manual/1.12/en/zend.layout.quickstart.html
// Returns null if startMvc() has not first been called
$layout = Zend_Layout::getMvcInstance();
So, if you didn't added this :
// In your bootstrap:
Zend_Layout::startMvc();
You will not access this -
Zend_Layout::getMvcInstance()->getView()
So try do this something like that:
Zend_Layout::startMvc();
Zend_Layout::getMvcInstance()->getView();
Is it possible to remove a script that was previously added like this?
$this->view->headScript()->appendFile("/js/my.js");
The situation here is that in my Bootstrap.php several JavaScript files are appended like in the above example but in a particular controller I want one particular JavaScript file not to be loaded. Is there a way to remove it during the initiation of the controller?
I am looking for something like this.
$this->view->headScript()->removeFile("/js/my.js");
This works, but really isn't a good practice but rather for exceptional purposes. I recommend trying to not load the unwanted scripts in the first place.
It is possible to remove scripts subsequently with a function like this one.
/**
* Removes a previously appended script file.
*
* #param string $src The source path of the script file.
* #return boolean Returns TRUE, if the removal has been a success.
*/
public function removeScript($src) {
$headScriptContainer = Zend_View_Helper_Placeholder_Registry::getRegistry()
->getContainer("Zend_View_Helper_HeadScript");
$iter = $headScriptContainer->getIterator();
$success = FALSE;
foreach ($iter as $k => $value) {
if(strpos($value->attributes["src"], $src) !== FALSE) {
$iter->offsetUnset($k);
$success = TRUE;
}
}
Zend_View_Helper_Placeholder_Registry::getRegistry()
->setContainer("Zend_View_Helper_HeadScript",$headScriptContainer);
return $success;
}
Note that the strpos function is used here. This will remove every script that has $src in its path. Of course you can change that to your needs.
It's an old question, but here is an alternative:
I used the minifyHeadScript and changed his helper adding this custom function:
/**
* Removes all script file.
*
*/
public function clearAllScripts(){
$this->getContainer()->exchangeArray(array());
$container = $this->getContainer();
Zend_View_Helper_Placeholder_Registry::getRegistry()->setContainer("Zend_View_Helper_HeadScript", $container);
}
Warning: Parameter 3 to showBlogSection() expected to be a reference, value given in /home/smartsta/public_html/includes/Cache/Lite/Function.php on line 100
I'm getting the above error displaying within my content areas on my Joomla site all a sudden, any suggestions?
Update: No such luck finding access to defined file and directory within godaddy ftp file directory, ftp, or Joomal C-panel.
Within FTP, I cannot find access to this particular file to investigate what is on line 100.
Within the Joomla panel, in Global Configurations, I was able to toggle 'error message' to none for atleast this error to be hidden. Within the cache directory I do not see any options to get into the folder, though it displays.
I also see this at the bottom of that c-panel screen, but just links to a joomla help site, and within the fields I do not see described area to toggle 'ON or OFF'
"Following PHP Server Settings are not optimal for Security and it is recommended to change them:
PHP register_globals setting is ON instead of OFF
"
Update2!:
I've found the file in question, below is the code. Line 100 only states:
global $$object_123456789;
application/x-httpd-php Function.php
PHP script text
<?php
/**
* This class extends Cache_Lite and can be used to cache the result and output of functions/methods
*
* This class is completly inspired from Sebastian Bergmann's
* PEAR/Cache_Function class. This is only an adaptation to
* Cache_Lite
*
* There are some examples in the 'docs/examples' file
* Technical choices are described in the 'docs/technical' file
*
* #package Cache_Lite
* #version $Id: Function.php 47 2005-09-15 02:55:27Z rhuk $
* #author Sebastian BERGMANN <sb#sebastian-bergmann.de>
* #author Fabien MARTY <fab#php.net>
*/
// no direct access
defined( '_VALID_MOS' ) or die( 'Restricted access' );
require_once( $mosConfig_absolute_path . '/includes/Cache/Lite.php' );
class Cache_Lite_Function extends Cache_Lite
{
// --- Private properties ---
/**
* Default cache group for function caching
*
* #var string $_defaultGroup
*/
var $_defaultGroup = 'Cache_Lite_Function';
// --- Public methods ----
/**
* Constructor
*
* $options is an assoc. To have a look at availables options,
* see the constructor of the Cache_Lite class in 'Cache_Lite.php'
*
* Comparing to Cache_Lite constructor, there is another option :
* $options = array(
* (...) see Cache_Lite constructor
* 'defaultGroup' => default cache group for function caching (string)
* );
*
* #param array $options options
* #access public
*/
function Cache_Lite_Function($options = array(NULL))
{
if (isset($options['defaultGroup'])) {
$this->_defaultGroup = $options['defaultGroup'];
}
$this->Cache_Lite($options);
}
/**
* Calls a cacheable function or method (or not if there is already a cache for it)
*
* Arguments of this method are read with func_get_args. So it doesn't appear
* in the function definition. Synopsis :
* call('functionName', $arg1, $arg2, ...)
* (arg1, arg2... are arguments of 'functionName')
*
* #return mixed result of the function/method
* #access public
*/
function call()
{
$arguments = func_get_args();
$id = serialize($arguments); // Generate a cache id
if (!$this->_fileNameProtection) {
$id = md5($id);
// if fileNameProtection is set to false, then the id has to be hashed
// because it's a very bad file name in most cases
}
$data = $this->get($id, $this->_defaultGroup);
if ($data !== false) {
$array = unserialize($data);
$output = $array['output'];
$result = $array['result'];
} else {
ob_start();
ob_implicit_flush(false);
$target = array_shift($arguments);
if (strstr($target, '::')) { // classname::staticMethod
list($class, $method) = explode('::', $target);
$result = call_user_func_array(array($class, $method), $arguments);
} else if (strstr($target, '->')) { // object->method
// use a stupid name ($objet_123456789 because) of problems when the object
// name is the same as this var name
list($object_123456789, $method) = explode('->', $target);
global $$object_123456789;
$result = call_user_func_array(array($$object_123456789, $method), $arguments);
} else { // function
$result = call_user_func_array($target, $arguments);
}
$output = ob_get_contents();
ob_end_clean();
$array['output'] = $output;
$array['result'] = $result;
$this->save(serialize($array), $id, $this->_defaultGroup);
}
echo($output);
return $result;
}
}
?>
It is not exactly an error. It is a warning.
Suddenly? Perhaps you have upgraded/updated your PHP version. Or changed PHP configuration to "strict mode".
The message "expected to be a reference, value given" means the called function expected to receive a reference, not a value. Look:
$something = 9;
show_section($something);
// here you are passing a variable
// this will be accepted as a reference
show_section(9);
// here you are NOT passing a reference
// here you are passing a VALUE
When you pass "by reference", the function can change the variable value... in the example above:
function show_section(&$parameter) {
$parameter = 'changed!';
}
Note the ampersand symbol & before the $parameter - this is how we specify a function requires a REFERENCE.
AFTER the function call, in the example above, the variable $something value will be the changed! string.
The line throwing the error is NOT the "global" one. It is the next:
$result = call_user_func_array(array($$object_123456789, $method), $arguments);
The problem here is that the function is being called indirectly by using the "call_user_func_array" function.
A solution would be transforming all arguments into references. Suggestion:
foreach ($arguments as $count => $value)
{
$param = 'param' . $count;
$$param = $value;
$arguments[$count] = &$$param;
}
Put the code above in the beginning of the call function, right after the following line:
$id = serialize($arguments);
Give this a try!
I would like to use YUI compressor with minify PHP rather than the default JSmin. Does anyone have experience setting this up?
Right now I am using the groupsConfig.php to combine the JS.
return array(
'jsAll' => array('//contenido/themes/bam/assets/js/jquery.js', '//contenido/themes/bam/assets/js/modernizr.js','//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/imgpreload.js', '//contenido/themes/bam/assets/js/history.js','//contenido/themes/bam/assets/js/ajaxify.js', '//contenido/themes/bam/assets/js/isotope.js'),
'jsHome' => array('//contenido/themes/bam/assets/js/easing.js','//contenido/themes/bam/assets/js/scrollable.js', '//contenido/themes/bam/assets/js/home.js'),
'cssAll' => array('//contenido/themes/bam/bam.css'),
);
As it says on the homepage:
Uses an enhanced port of Douglas Crockford's JSMin library and custom classes to minify CSS and HTML
I have the following code in config.php, but I get a 500 error when trying to view the combined js file:
function yuiJs($js) {
require_once '/lib/Minify/YUICompressor.php';
Minify_YUICompressor::$jarFile = '/lib/yuicompressor-2.4.2.jar';
Minify_YUICompressor::$tempDir = '/temp';
return Minify_YUICompressor::minifyJs($js);
}
$min_serveOptions['minifiers']['application/x-javascript'] = 'yuiJs';
It also appears that there are several lines in lib/Minify/YUICompressor.php that need to be configured, and I'm not sure if I'm doing it right:
class Minify_YUICompressor {
/**
* Filepath of the YUI Compressor jar file. This must be set before
* calling minifyJs() or minifyCss().
*
* #var string
*/
public static $jarFile = '../yuicompressor-2.4.2.jar';
/**
* Writable temp directory. This must be set before calling minifyJs()
* or minifyCss().
*
* #var string
*/
public static $tempDir = '../../temp/';
/**
* Filepath of "java" executable (may be needed if not in shell's PATH)
*
* #var string
*/
public static $javaExecutable = 'java';
I had the same problem on windows. It seems jar file needs to be executable in order to run yui compressor. So, i have to remove excutable check from YUICompressor.php
#132
private static function _prepare()
{
if (! is_file(self::$jarFile)) {
throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not a valid file.');
}
// if (! is_executable(self::$jarFile)) {
// throw new Exception('Minify_YUICompressor : $jarFile('.self::$jarFile.') is not executable.');
// }
if (! is_dir(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not a valid direcotry.');
}
if (! is_writable(self::$tempDir)) {
throw new Exception('Minify_YUICompressor : $tempDir('.self::$tempDir.') is not writable.');
}
}
and that works fine.