Strange behavior when returning view with custom Blade directive in Laravel - laravel

Currently I am working on a project where views need to be rendered through a custom Blade directive. However I came across a few (limitations?) errors I cannot solve (for a long time).
My custom Blade directive with tree different ways to output a view.
Blade::directive('lwField', function ($expression) {
// 1
return view('lw::module.field.field')->render();
// 2
return Blade::compileString('{!! view("lw::module.field.field")->render() !!}');
// 3
return Blade::compileString('#include("lw::module.field.field")');
});
The field view:
Get to the choppa!
The main view:
#extends('layout.default')
#section('main_content')
#lwField()
#endsection
The layout file:
// ... some cool html
#section ('main_content')
#show
// ... even more cool html
The following happens when I execute the three methods separately:
1 return view('lw::module.field.field')->render();
The fist time it executes it throws an error:
include(/somepath/storage/framework/views/b30c24f5b8fd420ef1a08edb52e92174e2dfe911.php): failed to open stream: No such file or directory (View: /somepath/resources/views/page/default.blade.php)
This is true since there is only one view in my cached folder:
// 5b27802352643346357e49b847d934736c36cd07.php
// The main view with the field view
<?php $__env->startSection('main_content'); ?>
Get to the choppa!
<?php $__env->stopSection(); ?>
The second time I run this it magically works. It will generate 3 other files:
// b30c24f5b8fd420ef1a08edb52e92174e2dfe911.php
// the main view with yielding layout view without field view
<?php $__env->startSection('main_content'); ?>
<?php $__env->stopSection(); ?>
<?php echo $__env->make('layout.default', array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>
// e4cec91e7d4adb5dac5c63e5bfa85ba9a258f664.php
// the layout file
// ...
<?php endforeach; $__env->popLoop(); $loop = $__env->getFirstLoop(); ?>
// ...
// ffd60653d8490007c272c527abef3a5ede092a33.php
// layout view and main view
// ...
<?php $__env->startSection('main_content'); ?>
<?php echo $__env->yieldSection(); ?>
// ...
It looks like it generates two files that are the same but one without the field view.
2 return Blade::compileString('{!! view("lw::module.field.field")->render() !!}');
3 return Blade::compileString('#include("lw::module.field.field")');
These methods will return a blanko page and generate two files in cache without showing/logging any errors.
// 5b27802352643346357e49b847d934736c36cd07.php
// Field view
Get to the choppa!
// b30c24f5b8fd420ef1a08edb52e92174e2dfe911.php
// Main view and field view
<?php $__env->startSection('main_content'); ?>
<?php echo view("lw::module.field.field")->render(); ?>
<?php $__env->stopSection(); ?>
This method will not generate the layout file.
Does anyone have a clue on what is happening. Maybe this kind of behavior is not strange at all and this is how Blade should work.

I have been working on a project that required me to do the same thing, the problem is that making a new Blade directive is not a good practice when you want to render another view, It's because of the Cache, every Blade directive is being cached so if you want to render dynamic data it will cause you a lot of problems.
Since I have tried a lot of options and you want to render another view file and not just push html to the blade directive, I suggest you to make a new helper or even a service that you can pass there the parameters and it will return the render function that outputs clean HTML so this way you can be sure that your content will be always dynamic and won't be cached.
TL;DR
Example:
In your helpers functions file put:
function render_my_view() {
return view(''lw::module.field.field'')->render();
}
So then in yout blade file you can use:
{!! render_my_view() !!}

Related

Severity notice: Undefined variable - images_model

This code works well in the "images" view under images_model:
<?php if($images_model):?>
<?php foreach($images_model as $images):?>
<div class="col-sm-4">
<div class="well">
<img src="<?php echo base_url()."uploads/".$images->name;?>" alt="" class="img-thumbnail">
The code in images_model is the following:
function save_image($data){
$this->db->insert('images', $data);
}
When I try to use the same code in the "wall" view (main_controller) I get the severity notice error saying "images_model" is undefined; even though I load the images_model in the main_controller or auto-load the both models:
$autoload['model'] = array('main_model', 'images_model');
I originally questioned the "foreach" code in the "images" view, but I thought if it works in one view shouldn't it also work in another if I load the related model? It just doesn't seem to be reading the images_model.
I'm just getting to know codeigniter a bit and would appreciate any feedback.
Are you passing the $images_model variable to your view from your main_controller ?
// Set your variable
$data['images_model'] = $images_model;
// Pass variable to view
$this->load->view('main', $data);
You typically shouldn't have access to a model directly in the view (following MVC principals). Your controller should get what it wants from the model, then pass it to the view.

What's good way to load header and footer view in codeigniter?

I'm using codeigniter 3x. I'm working on my website. I'm using include method in my view.
Like
<?php include('templates/header.php'); ?>
<h1>Home Page</h1>
<?php include('templates/footer.php'); ?>
Is this a good way to show header and footer in codeigniter.
Thank!
You are half your way, here is how you will be able to make it more dynamic, in your views file you should have a structure like this:
views
- header.php
- footer.php
- template.php
- home.page
In header.php you should have all your header and footer content which you wants to display on all pages.
Now in your template move all your includes.
template.php
<?php $this->load->view("header.php"); ?>
<?php $this->load->view($main_content); ?>
<?php $this->load->view("footer.php"); ?>
here you notice $main_content variable, it is dynamic file name which we want to load in our controller. So lets assume you have a controller like this:
public function home()
{
$data['meta_title'] = $this->lang->line('home_meta_title');
$data['meta_description'] = $this->lang->line('home_meta_description');
$data['meta_keywords'] = $this->lang->line('home_meta_keywords');
$data['main_content'] = 'home';
$this->load->view('template',$data);
}
$data['main_content'] = 'home'; is loading your home.php file, you can also load from subdirectories like 'directory/home'. You can also pass any variable like I gave you above example with dynamic meta.

How to display error or success message in a template file?

I want to show message on some condition in a template file(custom module template file).I am having following code.
<?php
if(count($collection)): ?>
<?php foreach($collection as $coll): ?>
some calculations
<?php endforeach; ?>
<?php else: ?>
<?php $message = $this->__('There is no data available'); ?>
<?php echo Mage::getSingleton('core/session')->addNotice($message);?>
<?php endif;?>
But this is not working properly. The message is displayed on other pages not on the same page.
If you really need to implement that right in the template, you may use the code below:
<?php echo $this->getLayout()->createBlock('core/messages')->addNotice('My Message')->toHtml(); ?>
But the solution described by Amit Bera sounds like a better way to resolve it.
Muk,According to your code
Mage::getSingleton('core/session')->addNotice($message);
add an notice to magento.This is code set notice to session and which is reflecting on page refresh according php session ,a session variable set value is reflecting after page refresh.
If you already added this notice on other page before came to your file then ,you need to add core/session to custom module template file controllers file.
Code is $this->_initLayoutMessages('core/session');
In controller you need below code in controller.
/* load the layout from xml */
$this->loadLayout();
$this->_initLayoutMessages('core/session');
/* rendering layout */
$this->renderLayout();
Read more at inchoo blog
I found that $this->loadLayout() is what reads and clears messages from the session, therefore if you add messages before calling $this->loadLayout() then those messages should be displayed on the current page.
Example:
public function chooseFileAction() {
// a quick and dirty way to find the larger out of post_max_size and upload_max_filesize
$post_max_size = ini_get('post_max_size'); $post_max_size_int = str_replace('K', '000', str_replace('M', '000000', str_replace('G', '000000000', $post_max_size)));
$upload_max_filesize = ini_get('upload_max_filesize'); $upload_max_filesize_int = str_replace('K', '000', str_replace('M', '000000', str_replace('G', '000000000', $upload_max_filesize)));
$maxsize = $post_max_size_int < $upload_max_filesize_int ? $post_max_size : $upload_max_filesize;
// display max file size to user in a message box
$msg = 'Max file size: ' . $maxsize;
Mage::getSingleton('core/session')->addNotice($msg);
$this->loadLayout();
$this->_title($this->__('Catalog'))->_title($this->__('File Upload'));
$this->_setActiveMenu('catalog/customfileupload');
$block = $this->getLayout()->createBlock('customfileupload/adminhtml_customfileupload_choosefile');
$this->_addContent($block);
$this->renderLayout();
}
Caveat: this is tested in Magento 1.9, not 1.7.

Display Block on specific views page

Im using views to display content ,, How can i show block only in the first page in the views and im enable the ajax in the views..
I tried with PHP in the Block visibility but I dont know how to get the first page in the views...
Portfolio = the views name
<?php
$url = request_uri();
$pos = strpos($url, "page");
if ($pos === false && arg(0) =='portfolio') {
return TRUE;
}
?>
you should have different page files for your pages, like "node--product_page.tpl.php"
you can add your view block inside your page, whenever you want using this code:
<?php echo views_embed_view('YourViewName[ex:product_list]', $display_id ='yourBlockViewName[ex:block_1]'); ?>

How to implement a sidebar in Zend Framework

How do I implement a sidebar in Zend Framework?
I know that I can use a placeholder or something similar in Zend_layout, but how do I automatically generate the code for the sidebar in my controllers without having to call a sidebar class within every controller?
My setup is as follows
Application
- modules
- blog
- other modules
I only want the sidebar for my blog module.
I have found this http://www.zfforums.com/zend-framework-components-13/model-view-controller-mvc-21/how-layout-sidebar-etc-2677.html but I do not understand the last part "just inject your layout, register it with the front controller ..."
You could just have a action and view in one of your controllers which renders the sidebar.
from the layout for the blog module you just call:
<? echo $this->action('action','controller','module',array('optionalparams'=>1); ?>
on the position where you want to have it. So one call to one action.
Rather than use the action stack and the action() view helper, you could render a "partial view script" that includes your sidebar elements.
# in your layout.phtml
<div id="sidebar">
<?php echo $this->render('blog/_sidebar.phtml'); /*relative to your view scripts directory*/ ?>
</div>
# in blog/_sidebar.phtml
<div id="blog_categories">
<?php foreach ($this->categories as $category): ?>
<?php echo $category->name; ?>
<?php endforeach; ?>
</div>
The render() view helper is used to render the content of another view script. It has the same scope as all your other view scripts, so if there are any variable assigned to the view, they will be available to your partial. So in the example above, the categories variable was set in the controller.
There is another view helper called the partial() view helper. This function is a little more expensive since it creates its own variable scope. In other words, none of your current view variables will be available. You will have a clean slate to work with, which means you must pass in any variables you need:
# in your layout.phtml
<div id="sidebar">
<?php echo $this->partial('blog/_sidebar.phtml', array('categories2'=>$this->categories)); ?>
</div>
# in blog/_sidebar.phtml
<div id="blog_categories">
<?php foreach ($this->categories2 as $category): ?>
<?php echo $category->name; ?>
<?php endforeach; ?>
</div>
I don't find myself using partial() very often since it is more expensive, and I rarely need to create a separate context.
As far as setting up the variables for use in the sidebar partial ($this->categories in this example), I have used a number of different methods depending on the particular problem. If it's specific to a controller action, I will write the code and assign it in the view script:
# controller
public function somethingAction()
{
$this->view->categories = $this->_getCategoriesForThisParticularAction();
// other controller code
}
If my code is more generic to all the actions of the controller, I will utilize the controller's preDispatch() function. If it's more generic to multiple controllers, I will put the code in the init() of my base controller (a controller the most of my controllers extend).
Sometimes I do not even put the code in my controller. If it's simple enough, I just stick the code in the partial. If it's a little more complex, I will move it to a view helper. This may break the MVC pattern, but I think it really depends on the particular case in order to determine the best placement.
If you are using Zend_Layout, just add the sidebar with the Action viewhelper as Rufinus said.
in your layout script:
<div id="sidebar">
<?php echo $this->action('action', 'controller', 'module', array('optionalparams'=>1)); ?>
</div>
<div id="content">
<?php echo $this->layout()->content; ?>
</div>
This should meet the requirements posted in your question.

Resources