My question is about nesting layouts in Laravel. I am trying to do so as seen below, which works in most cases but produces unwanted results in others.
\\MasterLayout
--code for header, navbar, etc.
#yield('content)
#yield('scripts)
\\SubLayout
#extends('layouts.MasterLayout')
#section('content')
<div>
#yield('sidebar')
#yield('main')
</div>
#endsection
#section('scripts')
<script>scripts needed in all the relevant views</script>
#yield('scripts.sub')
#endsection
\\Views
#extends('layouts.SubLayout')
--some code
#section('sidebar')
--sidebar code
#endsection
#section('main')
--main code
#endsection
#section('scripts.sub')
<script>scripts only needed in this view</script>
#endsection
In my own case, I have a further layer of nesting (a subsublayout). My controller simply redirects to the view without doing anything special. E.g.,
public function start()
{
return view('createproject/start');
}
This works pretty well in many cases, but there are some problems. For example, I can't simply include php files in the SubLayout that are needed in the views. Those includes have to go in the file in which they are being used in order to gain access to their functions. Also, placing <div></div> tags directly outside an #yield sometimes has a different effect than placing them directly inside the #section to which the #yield points. Also, while the pages work, I have gotten some strange warning messages such as that I have declared DOCTYPE multiple times or not at all, when neither is true as far as I can tell. So while the method of nesting seems to work, it's a bit unwieldy and I'm not convinced it represents best practice.
Hence, my question for the community is this: Is my suggested method of nesting layouts generally appropriate (perhaps with some caveats that address the problems I'm having) or does it exhibit some fundamental problem/confusion?
There is a related Stack Q&A that I've found here: Laravel multiple nested views but the nest() function referenced there is no longer discussed in more recent versions of the Laravel documentation (have I missed it?), so I wonder if it's still needed.
you can use components and slots for that
components-and-slots
Related
Im using Laravel 7 so I didnt think this was going to be an issue.
Just a note on my installation, it was an upgrade from 5.3.
My issue is with a custom Blade directive I created.
It is aded additional quotes around the input
I added a dd() to see why my Helper didnt work.
My ServiceProvider
Blade::directive('setting', function ($expression) {
dd($expression);
return SettingHelper::value($expression);
});
View file
#setting('theme_public')
Output of dd()
"'theme_public'"
Expected output
'theme_public'
I dont know why the extra quotes are being added.
You are right, I get the same behavior with a fresh laravel 7 installation.
I created some little tests, to see what's going on. I think the behavior is best explained like this. Imagine you are calling a view with one variable:
return view('welcome', ['var' => "Hallo"]);
You have a custom blade directive like this:
Blade::directive('dirtest', function ($expression) {
dd($expression);
});
If you use that in your template the output is this:
#dirtest($var)
// output of dd in the browser:
"$var"
So it seems like the blade directives are just meant to replace some shorthand directive with more verbose php code. The actual code get's executed later in the blade templating engine. That makes sense, since blade templates are also cached for faster execution. In the cached version that custom directive is already embedded and your custom function doesn't get fired anymore. I hope that explanation makes sense to you.
What that means for you
It really depends on your use case. If you have a custom directive, that only gets passed constant strings, you could probably get away with just writing:
#setting(theme_public)
But if there's just a slight chance, that you might pass in a variable from time to time, like
#setting($theme)
You really have to return code, that utilizes that variable and can be evaluated later.
I have these "containers" which each holds one major section of my code. A page is therefore built up of a few containers, and they all look and behave the same. In my route directory, I have the following architecture
app
/containers
/Main
MainContainer.php
ContainerName1.php
ContainerName2.php
...
/Side
SideContainer.php
ContainerName3.php
ContainerName4.php
...
/Aux
AuxContainer.php
ContainerName5.php
ContainerName6.php
...
BaseContainer.php
So MainContainer.php, SideContainer.php, and AuxContainer.php all extend BaseContainer.php, and each ContainerName#.php extends the appropriate container. I currently have all the HTML/Views done within these containers themselves. But I wanted to move all HTML/Views to a template.
Should I have the templates in the /views folder, or should I keep it in this /containers folder? The reason why I may want to keep it in the /containers folder is because there will be a base.blade.php, and main.blade.php (and side/aux), and then one per ContainerName#. So it may stay cleaner if they are all there?? If I can do this, how do I call it?
I think this is partially a matter of opinion, but I'll toss my opinion in here and I suppose people can downvote me if they disagree.
I think it's better to keep all your views in /views, mostly because that's the appropriate and expected place for them. If anyone other than you were to maintain this project, they'd look for views in /views, and I think they'd be throughly confused if they were stored in some containers.
Here's what my view structure looks like in my project:
views
/layouts
main.blade.php
/includes
analytics.blade.php
navbar.blade.php
flair.blade.php
...
/account
main.blade.php
public-listing.blade.php
public-profile.blade.php
...
/game
listing.blade.php
settings.blade.php
...
about.blade.php
contact.blade.php
help.blade.php
I have my main templates in layouts (which is essentially my stock bootstrap code), I have little bits that I'll include in includes (things that will never be webpages on their own, but make other web pages work), and the rest goes in a sub folder depending on the controller. From each of my "full" views, the top line is #extends('layouts.main') and that makes sure it inherits the correct layout (if there was more than one, although there isn't in my example).
I think something like this could easily work for your project, and would go a long way in making it easier for you and anyone else to maintain.
I'm trying to manipulate some code inside of a phpBB template file. Essentially, the forum descriptions contain some markup that needs to be converted before being displayed.
I am able to display the description using code similar to the following:
<!-- ELSEIF forumrow.FORUM_DESC -->
<li class="row"><span>{forumrow.FORUM_DESC}</span></li>
<!-- ENDIF -->
However, how can I wrap the forumrow.FORUM_DESC inside a html_entity_decode() function or something similar? I've tried moving the {forumrow.FORUM_DESC} into blocks, but the variables are different.
Probably not the best way to solve this, but I was able to modify the code to look something like this:
<!-- PHP -->echo html_entity_decode($_forumrow_val['FORUM_DESC']);<!-- ENDPHP -->
I was able to determine the values of the variables with a backtrace:
var_dump(debug_backtrace());
Again, may not be the best solution, but hopefully it helps someone else that hits this snag.
I've been scouring the net in pursuit of this one. Magento Commerce comes us dry for me. grepping core code, reading Alan Storm, perusing Inchoo, and even finding related questions on SO turn up no answers for me.
With that said, my problem is with a transactional email template that works when processed from the backend but not from the frontend. Here's a snippet:
<td width="100%" colspan="2" align="left">
<!-- inject products quote table -->
{{block type="adminhtml/sales_quotation_email" template="sales/quotation/email_quote_items.phtml" inherits=$template quote=$quote salesrep=$salesrep}}
<!-- inject cross-sell products table -->
{{block type="adminhtml/sales_quotation_email" template="sales/quotation/email_quote_cross_sells.phtml" inherits=$template quote=$quote salesrep=$salesrep}}
</td>
In the backend, these blocks are rendered as expected. In the front-end, everything above and below these block directives is rendered, but it appears that the directives die in processing when it comes time to render the template. No errors are thrown.
I followed the advice here, but no luck. Originally I tried to use setDesignConfig on the email template model, but that didn't work. I even tried to set the area as an attribute in the directive, but that also did not work. A colleague suggested that I have two copies of the above templates: one set in design/adminhtml and the other design/frontend. I'd rather not have to worry about extra maintenance. Plus, I fear that I'd encounter the same problem if the block type specified in the directive comes from adminhtml. I don't want that solution.
So what am I doing wrong? What do I not understand?
How does Magento resolve the real path to the template, and is a template forced to reside in the area of its parent block?
Help is needed! Thanks.
SOLVED
I found a related post on Magento Commerce that put me back on track. I started dumping out the design configuration in two controllers: 1 in frontend and one in adminhtml. I noticed immediately that theme information was missing in the frontend request. See some sample output from my frontend controller:
Mage_Core_Model_Design_Package Object (
[_store:protected] =>
[_area:protected] => frontend
[_name:protected] => mypackage
[_theme:protected] => Array
(
[layout] =>
[template] =>
[skin] =>
[locale] => mytheme
)
[_rootDir:protected] =>
[_callbackFileDir:protected] =>
[_config:protected] =>
[_shouldFallback:protected] => 1 )
Notice that layout, template, and skin are empty in the theme property. When I dumped the design configuration from an adminhtml controller, these properties were set.
So going back to my frontend controller, I added the following line before I instantiated my email template model:
Mage::getDesign()->setArea('adminhtml');
Mage::getDesign()->setTheme('mytheme');
And poof! It worked! My blocks directives were processed and the fully rendered content was returned as expected.
So although my thinking was correct to set the area, that alone wasn't enough. I also has to configure the theme.
I'm happy with the solution. I hope it helps others. But to fully answer this question, I'm still curious if anyone knows why package information is missing from the design configuration during a frontend request. Does it have to do with the block type in the directive coming from adminhtml? That would make sense, because adminhtml has no need to worry about theme information. I just don't know where those decisions would be made in core code. See update below.
UPDATE:
Learned even more since the original post. My question gave a code sample that built a block of a type that came from adminhtml. The path to the template, I thought, was resolving to the front-end, and that was why no template could be found. That wasn't actually the case. An adminhtml block, because of its class naming convention, will look in design/adminhtml/package/default/module for your template.
However, in my particular Magento installation, I have a design override in local.xml that changes the admin theme so that it admin requests check design/adminhtml/package/mytheme/module for templates. And that is where my phtml templates are stored. So on a front-end request, the controller has no clue about this override, and is only building up the design configuration based on what is set in the store configuration for the particular package and theme.
In summary, my call to setTheme() must utilize that modified config data, like so:
Mage::getDesign()->setTheme(
(string) Mage::app()
->getConfig()
->getNode('stores/admin/design/theme/default')
);
I guess that goes to say, then, that a simple call to setArea() would be sufficient for most installations.
Finally, you will need to revert the design configuration changes after your work is done, otherwise subsequent actions might produce undesired results.
I am developing an Application in Bonfire.
They have extended the form helper.
Is there a way to call the original form helper from Codigniter without removing the extended one from Bonfire?
"Helpers" are just files with PHP functions in them. They aren't actually "extended", Codeigniter loads it's default helpers after loading yours, and checks if you "overwrote" a function like so:
if ( ! function_exists('form_open'))
{
function form_open() {/* default code */}
}
So unfortunately, no - there's no way to call the original function if you already declared your own.
HOWEVER: It appears that Bonfire does the exact same thing, checking with function_exists, so if you want to - you should be able to load your own form helper before it, but you still cannot simply load the original one without hacking Bonfire and removing the functions (which could have terrible side effects).
Faced the same prob, user742736's comment is the only answer that solved the prob.
Explained in detail, may be this can help some one
You can create your own helper function with out the divs surrounding the drop down here
bonfire/application/helpers/MY_form_helper.php
make a copy of the function form_dropdown, name it like form_dropdown_plain
modify the last few lines of the function to output with out divs
call form_dropdown_plain instead of form_dropdown