Multiple #foreach in views - Laravel - php

I need to output various #foreach loops throughout my blade template, however they all target the same table in my database, just fetching different fields. As an example, I am using #yield in my main layout and #section in the views for title/descriptions tags etc etc:
#section('title')
#foreach($store_listings as $fetch)
Website stores - {{ $fetch->city }}, {{ $fetch->country }}
#endforeach
#stop
#section('description')
#foreach($store_listings as $fetch)
List of Stores in {{ $fetch->city }}, {{ $fetch->country }}.
#endforeach
#stop
Then in layout.main:
<title>#yield('title')</title>
and
<meta name="description" content="#yield('description')" />
This repeated #foreach loops are present in other sections of my views on other pages. I try to work by the DRY method. What are the suggestion here to save me entering multiple foreach loops when all I wish to do is call some variables? I don't want to have my controller to handle this business either.
Thanks

One thing you can do in this case it to use a partial, let's say views/_partials/storeList.blade.php:
#foreach($store_listings as $fetch)
{{$title}} {{ $fetch->city }}, {{ $fetch->country }}
#endforeach
Then in your main view you just call it:
#include('_partials.storeList', array('title' => 'Website stores -'))
#include('_partials.storeList', array('title' => 'List of Stores in'))

Related

Easyadmin 3 - How to render embedded form?

I am trying EasyAdmin, and I am completely lost.
I have entity A which contains a relationship with entity B (which contains multiple fields).
In Entity A's CrudController, if I want to display fields from the relation (so, Entity B), how am I supposed to go about it?
In my current case I have a Portfolio entity that has a relationship with UserDetails (and which contains several fields that I therefore want to display in the form of the Portfolio entity)
I created a FormType for my UserDetails class, as we normally would. And in my CRUD controller, for the Portfolio entity, I put this:
public function configureFields(string $pageName): iterable
{
return [
IdField::new('id'),
FormField::addPanel()->setProperty('userDetails')->setFormType(ProjectUserDetailsType::class)
];
}
Is this the right way to go? Will the fields contained in this FormField be mapped correctly?
On the other hand when rendering, this "subform" is centered, unlike the others.
When you try to embed a single object or form you could follow this doc
If you want also embed a collection of objects there is a way for that using what is called prototypes.
For rendering the form and styles you could render each part separately and adding the proper styles on twig files or inside the form definition.
#rendering with twig
{{ form_label(form.field, 'label', { 'attr': {'class': 'foo'} }) }}
{{ form_widget(form.field, { 'attr': {'class': 'bar'} }) }}
#rendering inside html tags
<div class="form-control">
<i class="fa fa-calendar"></i> {{ form_label(form.dueDate) }}
{{ form_widget(form.dueDate) }}
<small>{{ form_help(form.dueDate) }}</small>
<div class="form-error">
{{ form_errors(form.dueDate) }}
</div>

Use blade value inside a component

At the moment I can successfully display some generated content in my blade view by calling a variable with a key, like this:
<div>
{{ $data['key'] }}
</div>
What I would like to achieve, is to reuse the key for a class name for example. The reason for that is that I want to easily access this content with JavaScript by using a selector. Something that would look like this:
<div class='key'>
{{ $data['key'] }}
</div>
This code work, but as I have many fields, I would like to avoid duplicating the key. To achieve that, I thought of creating a blade components, and pass the key in the slot. So that I can reuse this key both in the class name, and in the placeholder for data.
But it seems that my variable {{ $data }} is not accessible from my component file, as it throws the error: $data is undefined.
Here is my code:
<!-- In main.blade.php -->
#component('my-component')
key
#endcomponent
<!-- In my-component.blade.php -->
<div class="{{ $slot }}">
{{ $data[$slot] }}
</div>
I am not familiar to Blade so I am open to another approach if necessary.
You should pass your data and key as arguments to your component, thereby being more explicit. You don't need to use a slot for this, as a slot is generally used for blocks of text or HTML, not for simple attributes.
Create your component like this,
<div class="{{ $key }}">
{{ $data[$key] }}
</div>
And then render it like this
#component('my-component', ['data' => $data, 'key' => 'key'])

Laravel markdown mail - multiple templates. How to define path for #component('mail::*')

As detailed in config/mail.php, the default markdown mail folder is in views/vendor/mail
'markdown' => [
'theme' => 'default',
'paths' => [
resource_path('views/vendor/mail'),
],
],
I have created a new template in views/templates/1/mail. Change the path in the config and this works fine.
How can I use both the default vendor/mail folder as well as my new template for different notifications?
Adding my path to the mail config kind of works, but this is more to add additional files to the current template and requires that all files have unique names across every folder.
I can of course namespace the entire template path inside each blade file through to the HTML folder, but is there a more elegant way to hook up the mail::xxxx helper?
#component('templates/1/mail/html.layout')
To use mail::button type format, you have to create hint for that keyword, which is nowhere to be found in Laravel documentation.
As an alternate solution, this is how I'm using multiple layout for the Laravel notification:
Clone you existing mail (project/resources/views/vendor/mail) folder and customize the new layout. Inside mail folder you can customize the complete design. Files under this folder, provides blocks level changes to your email body.
Next, You have to clone email.blade.php file under notifications (project/resources/views/vendor/notifications), and customize it as per your need. This single file is the skeleton of your email.
Modify your email notifications to add view() or markdown() as per your need. In your Notification's 'toMail' function, chain the below line:
->view('vendor.notifications.custom_layout')
So, it will look like this:
return (new MailMessage)
->subject(__('emails/registration.subject'))
->greeting(__('emails/registration.failed.greetings', ['recipient' => $this->learner->username]))
->line(__('emails/registration.line_1'))
->line(__('emails/registration.line_2', ['username' => $this->username]))
->action(__('action.log_in'), "https://{$loginURL}")
->view('vendor.notifications.custom_layout');
All the file naming convention will change from mail::message to vendor.custom_layout.html.message
This is how your custom file (under notifications folder) will look like:
#component('vendor.custom_layout.html.message')
{{-- Greeting --}}
#if (! empty($greeting))
# {{ $greeting }}
#else
#if ($level == 'error')
# #lang('Whoops!')
#else
# #lang('Hello!')
#endif
#endif
{{-- Intro Lines --}}
#foreach ($introLines as $line)
{!! $line !!}
#endforeach
{{-- Action Button --}}
#isset($actionText)
#component('vendor.custom_layout.html.button', ['url' => $actionUrl])
{{ $actionText }}
#endcomponent
#endisset
{{-- Outro Lines --}}
#foreach ($outroLines as $line)
{!! $line !!}
#endforeach
{{-- Salutation --}}
#if (! empty($salutation))
{{ $salutation }}
#else
{{ __('label.thank_you') }}<br>{{ __('label.xyz_team') }}
#endif
{{-- Subcopy --}}
#isset($actionText)
#component('vendor.custom_layout.html.subcopy')
{!! __('emails/common.footer_notice', ['actionText' => $actionText]) !!}
[{{ $actionUrl }}]({!! $actionUrl !!})
#endcomponent
#endisset
#endcomponent
These are the only changes which are required to make a customized view for your emails.

Laravel Blade Template With Breadcrumbs

I have a template admin.blade.php that contains this code:
#yield('breadcrumbs', Breadcrumbs::render(Request::route()->getName()))
And in my child files I either ignore breadcrumbs or I would like to do something like:
#section('breadcrumbs')
{{ Breadcrumbs::render(Request::route()->getName(), $event) }}
#endsection
The problem is that it seems that the default yield content is still being triggered and when the function gets called I get an error.
Too few arguments to function
DaveJamesMiller\Breadcrumbs\BreadcrumbsServiceProvider::{closure}(), 1
passed in
C:\xampp\htdocs\msu\vendor\davejamesmiller\laravel-breadcrumbs\src\BreadcrumbsGenerator.php
on line 68 and exactly 2 expected (View:
C:\xampp\htdocs\msu\resources\views\event\station\edit.blade.php)
Which I understand, so my question is how do I achieve what I am trying to do in blade?
I also tried doing #section #show and section #stop but that seems to just hide the sections and give me the same error.
Any help is greatly appreciated.
You could create a component to handle the if case you are going to need:
<!-- resources/views/breadcrumb.blade.php -->
#if (isset($slot) && !is_null($slot))
#section ('breadcrumbs')
{{ Breadcrumbs::render(Request::route()->getName(), $slot) }}
#endsection
#endif
Then inside your child view, you can call your component:
<!-- resources/views/child.blade.php -->
#component('breadcrumb', ['slot' => $event]) #endcomponent
You can update the variable name in the component to whatever you like.
For more information about components: https://laravel.com/docs/5.6/blade#components-and-slots

FOSUserBundle Login, Registration, ForgotPassword on the same page

I've overrided the default layout of FOSUserBundle by placing a layout.html.twig in app\Resources\FOSUserBundle\views.
I also have overrided some other templates (like login, register and resetting password) by placing new files in the corresponding directory:
app\Resources\FOSUserBundle\views\layout.html.twig
app\Resources\FOSUserBundle\views\Registration\register.html.twig
app\Resources\FOSUserBundle\views\Resetting\request.html.twig
app\Resources\FOSUserBundle\views\Security\login.html.twig
I would like to render the register-form, the login-form and the reset-password-form on the same page. For that I'm using twigs render controller method:
<div class="login" data-lbg="teal">
{{ render(controller('FOSUserBundle:Security:login')) }} // foo
{{ render(controller('FOSUserBundle:Registration:register')) }} // bar
{{ render(controller('FOSUserBundle:Resetting:request')) }} // baz
</div>
However, this just outputs the word "foo" and doesn't extend my layout.html.twig. So it just gives me a blank page with "foo" on it.
Is there something broken or am I doing something wrong?
Best
Christian
I created an specific controller for rendering the three forms, which seems to be working. In the corresponding view script:
{% extends 'FOSUserBundle::layout.html.twig' %}
{% block body %}
{{ render(controller('FOSUserBundle:Security:login')) }}
{{ render(controller('FOSUserBundle:Registration:register')) }}
{{ render(controller('FOSUserBundle:Resetting:request')) }}
{% endblock %}
Unfortunately, if there are validation errors, the user will be redirected to /login, /register and /resetting/request, which templates are not extending the login layout. At the moment, the user get a white page with the form on it. :/

Categories