Save blade templates to database rather than file - php

I want to save my blade templates to database, because the header and footer of each page is customizable for the user. I want to let my users create the layout themselves and then for each request from a given user, I want to serve the page, using the layout specified by that user.
The necessary variables that are passed by the controller are provided to them in the documentation.
Note: I trust my users. They are all stake-holders of the project and are programmers, so server side code execution is acceptable.

Although this is an old post but just in case someone stumbles across it like I did. I achieved similar while using the Laravel Framework, by saving the view in database such that, whenever I need to display the view, I retrieve it from DB, and load it into a file using the file_put_contents() php function and render it with the view() method. For example;
$blade = DB::table('pages')->where('name', 'index')->first();
file_put_contents('template.blade.php', $blade->view);
//Note if I also need to pass data to the view I can also pass it like so
//$data = ['page_title' => 'Testing Blade Compilation using views Saved in DB'];
// return view(template, $data);
return view('template');
While again in my own case for added security, I created base templates with the blade templating scheme & injected user created inputs into the template after sanitizing the generated input using HTMLPurifier and rendering the view. For example
$view = view('base.template')->render();
//similarly like the above I can load any data into the view like so
//$data = ['page_title' => 'Testing Blade Compilation using views Saved in DB'];
//$view = view('base.template', $data)->render();
$purifier = new HTMLPurifier(HTMLPurifier_Config::createDefault());
$with_purified_input = $purifier->purify($user_generated_input);
str_replace('view_variable', $with_purified_input, $view);
return $view;

I realised that I can improve security and caching if I just let them insert the static content only. The only thing I need to change is the main content, so I can just let them set a token where the content is to be placed. As is in the above answer by #huzaib-shafi , I did the following...
//In controller
$content = View::make('final',compact('data'));
$token = "<meta name='_token' content='" . csrf_token() ."'";
$scripts = View::make('final_scripts',compact('data'));
$view = str_replace_first("<%content%>", $content, $templateInDatabase);
$view = str_replace_first("<%token%>", $token, $view);
$view = str_replace_first("<%scripts%>", $scripts, $view);
return $view;
This enforces them to use bootstrap in their template, because I use bootstrap styles in my blade templates, but it is acceptable in my case.

I asked and answered a similar question some days ago. So far as I know, Blade doesn't process view content from database columns. Although you can use compileString() method of View. But you should have a look at the following questions.
Extend Blade Template from Database stored string
Let users create custom blade layouts / store in database

In Laravel 9 you can use blade Facades to render from DB:
use Illuminate\Support\Facades\Blade;
return Blade::render('Your Blade Content {{ $parameter1}}', ['parameter1' => 'Name']);

Related

User Defined PDF Templates in Laravel 6

Currently building a system that requires users to design a custom template for a PDF document generated by the application. To achieve this, I have saved a blade template in the database to be retrieved when the document is about to be converted into a PDF document.
I know Laravel's View component can pick up a blade template from the file system and render it as an HTML document. However, to achieve my objective, this component should be able to read a text field fetched from the database. This is not currently possible with Laravel and I suspect is largely due to security reasons.
The question now is, how else can this be achieved using Laravel or what may be the recommended way to get this done?
Based on your comments and re-reading your initial question, my best guess is that you need a macro replacement function. This is the method I use for email templates in my own applications, which are stored in the database. It sounds similar to what you are attempting to do.
Helpers.php
Some autoloaded helpers file.
if (!function_exists('macro_parse')) {
function macro_parse($body, $haystack, $pattern = '/{{([^}]+)}}/')
{
$replace = preg_replace_callback($pattern, function ($needle) use ($haystack) {
return $haystack[$needle[1]];
}, $body);
return $replace;
}
} else {
Log::error("macro_parse is already defined");
}
Usage
// a simple template example...
// you would retrieve this template from the database
$template = '<div>{{some_macro}}</div>';
// key/value pairs can be set from database values
$macros = [
'some_macro' => 'it works!'
];
// parse the template
$parsed = macro_parse($template,$macros);
dd($parsed); // <div>it works!</div>
You can then pass the filled template to the PDF generator.

Laravel equivalent or alternative for CodeIgniter

I am trying to figure out how to do the equivalent of the following in Laravel that I would do in CodeIgniter all the time to build views:
$section = $this->load->view('pages/about', $data, TRUE);
This would allow me to echo $section in another view file and then when that view was called the normal way, it would render it. I am not sure how to do something like this in Laravel.
UPDATE
I figured it out. What I was needing was Laravel's HtmlString class to take a string and convert it to html markup to the view file.
You would need to use the View Facade, so make sure to include it with an "Use" statement in your Controller, but basically is this:
$html = View::make('pages/about', $data)->render();
The render() method will just render the view in HTML, instead of returning it as a Response object like the view() helper function does.
There are several ways to do so, try this:
return view('admin.profile', $data);
Read through this doc:
https://laravel.com/docs/5.5/views

Silverstripe customize controller data/variables

I'm trying to return search results to a new controller than where the search action was performed from. Problem is Results is never accessible from CustomSearchResultPage.ss. I've added inline comments for what I think is happening, am I right in my thinking here?
// Customise content with results
$response = $this->customise(array(
'Results' => $results ? $results->getResults() : '',
));
if ($results) {
$response = $response->customise($results);
}
// Use CustomSearchResultPage.ss template
$templates = array('CustomSearchResultPage', 'Page');
// Create a new CustomSearchResultPage page
$page = CustomSearchResultPage::get_one('CustomSearchResultPage');
// Build a controller using the CustomSearchResultPage
$controller = CustomSearchResultPage_Controller::create($page);
// Add the custom data to the newly minted controller
$result = $controller->customise($response);
// Return the controller and tell it how to render
return $result->renderWith($templates);
The page seems to render as expected just the variable is always empty...
Your explanation is a little hard to follow I'm afraid. So I'm answering for what I can ascertain as below:
Performing a search. This requires loading a controller to do as such.
Customising the current controller with the results
RE-customising the current controller with itself.
Setting the template for the current (double customised) controller.
Disregarding all of the above.
Fetching a random page (or an empty record).
Creating a controller for the empty page.
Customising the new controller with the customised controller of the current controller customised with itself.
Returning that page, which shows no results.
You need only stop at step 4 (skip step 3), and return the customisation ($response).
If there is some reason you think you need another controller however (which seems superflous, but who knows), creating and then customising that one (only) before returning it would be better.
Being that you have only used this second controller for rendering a result, the URL will not have changed or anything. The whole thing seems beyond requirements.
A much more simple way to render a result from this action would probably be:
return $this
->customise(['Results' => $results ? $results->getResults() : null])
->renderWith(['CustomSearchResultPage', 'Page']);
(from the top of my head, may need a little refining).

how to execute php code on every time load website on laravel 4.2?

I have dynamic menu on header which i get its content form database, so i want to know WHERE & HOW can implement code to get data form database to be defined on whole web application? without need to put code on each class responsible for load view.
$categuries_list = DB::table('categories')
->where('parent', '=', 2)
->lists('name', 'id');
I think to cache what i need but on this case i will put code on each class load view(so that is bad solution).
This is exactly what view composers are for.
View::composer('header', function($view)
{
$categuries_list = DB::table('categories')
->where('parent', '=', 2)
->lists('name', 'id');
$view->with('categuries_list', $categuries_list);
});
Just swap out the header with the actual name of the view which contains the header.
This code can go anywhere which is being autoloaded.
Can read about view composers in the documentation. http://laravel.com/docs/4.2/responses#view-composers

Two controllers for one view, CodeIgniter?

Hey guys, I am new to CodeIgniter and need some help. I have a controller that formats the content area of a post. The problem is that I also need to create a sidebar that contains dynamic groups, and a right column that contains recent posts. This isn't hard, the problem I'm running into is that I want the sidebar, and right column on every page, and I don't want to recode the same bits to get the data in every controller.
What would be the best way to do this without copy/paste?
There are a lot of ways to do this.
1) Templating: This is my preference for most cases (because my templates are complex), I render my view into a variable using something like:
$content = $this->load->view('myview', $page_data, true);
Then I load it into the template parser (fyi you could load it into another view too) like this:
$this->load->library('parser');
$data = array(
'page_title' => 'My Page Title',
'page_content' => $content,
'side_bar' => side_bar(), // function which generates your side bar
'right_col' => right_col() // function which generates your right column
);
$this->parser->parse('my_template', $data);
Then your template is like:
<html>
<head>
<title>{page_title}</title>
</head>
<body>
<div>{side_bar}</div>
<div>{page_content}</div>
<div>{right_col}</div>
</body>
</html>
2) Load another view in your view: (assumes you menu is a view not a controller) Something like this:
<?php $this->load->view('menu_view'); ?>
3) PHP Includes: exactly how you would do it in plain PHP (just include a url which points to a controller which returns a menu), Something like this:
<?php include("/common/sidebar"); ?>
Codeigniter will render that page and then include it.
4) AJAX.. i use this if the content in the "template" content is less important, like banners, suggested related item lists and such.
Use PHP to generate a static HTML page, such as side_bar.html...
Then you can include it on other pages.
You could look into HMVC. It's especially suited for "widget"-type areas like you are talking about.
Essentially what you will do is create two full MVC structures - one for your sidebar and right column, including a controller, a model(if required), and a partial view. Then, you can call this controller directly from the main view to pull the required content in to the page.
To actually call it from within a view, just place the following in the markup wherever you want the sidebar to appear:
<?php echo modules::run('module/sidebar/index'); ?>
The index isn't required, but I put it there to demonstrate that you can call different methods using modules::run(). You can also pass an unlimited number of parameters to modules::run().
In code igniter, there is an optional third parameter to $this->load->view that lets you return a rendered view as a string, which can in turn be used for assignment. What you can do is create a master template, that has all the common parts, as a very simplified example:
<html>
<head>
</head>
<body>
<?php echo $sidebar; ?>
<?php echo $content; ?>
<?php echo $right_column; ?>
</body>
</html>
Then you can create a private function in your controller to populate the dynamic content of your common parts, and combine them with your content and master template:
private function BuildTemplate($view, $data) {
// Generate sidebar content
$sidebar_data['...'] = 'blah blah';
$master_data['sidebar'] = $this->load->view('sidebar', $sidebar_data, true);
// Generate right column data
$right_data['...'] = 'blah blah';
$master_data['right_column'] = $this->load->view('right_column', $right_data, true);
// Now load your content
$master_data['content'] = $this->load->view($view, $data, true);
// Merge it into the master template and return it
return $this->load->view('master' $master_data, true);
}
Then in your appropriate controller method:
public function index() {
$data['...'] = 'blah';
echo $this->BuildTemplate('index', $data);
}
Which will pull everything together for you. You can optionally add extra arguments to BuildTemplate if you want to add things like page specific titles or scripts.
I'm not sure if your problem is in the view, or in the (dynamic) data to be shown in the (common parts of) that view.
If it's the later (as seems to suggest the phrase 'I don't want to recode the same bits to get the data in every controller'), then you have several options. For example.
Put the logic to get the 'common' data in some function outside the controller, as a helper or inside some model, and call it from your controllers.
Make your controllers inherit your own custom controller, that implements that data gathering function.
Refactor your two controllers into a single controller, with different functions for each scenario.
1-Create a custom library class in library folder with the below code
if (!defined('BASEPATH')) exit('No direct script access allowed');
class LoadView{
function __construct(){
$this->CI =& get_instance();
}
function load_view($page){
$this->CI->load->view('header');
$this->CI->load->view('sidebar');
$this->CI->load->view($page);
$this->CI->load->view('footer');
}
}
2-Now load this library in your controller like this
$this->load->library('loadview');
3-Now call the library method and simply insert your page name and you don't have to include header,sidebar and footer again and again as they will be dynamically included by your library.
$this->loadview->load_view('about.php');

Categories