Laravel Mail issue using nested #components with markdown - laravel

I am experiencing a problem where the code works but sometimes it fails to display the proper info in the outermost #component; the logo it shows is wrong, like if it's caching the outermost layout and using it on the next call, but with outdated info
The issue happens while sending emails, which are run on queues.
The relevant part of the code is as follows:
1: the mail I'm trying to send (works 100% of the time)
markdown.blade.php
#component('mail::message')
# #lang('emails.bookingRequestReceipt', ['user' => $association->person->account->first_name, 'school' => $bookingRequest->school->name])
{!! html_entity_decode($custom_intro) ?? '' !!}
#endcomponent
2: the message component (works 100% of the time)
#component('mail::layout')
<!-- THIS IS THE RELEVANT PART -->
{{-- Header --}}
#slot('header')
#component('mail::header', ['url' => $school['url'] ?? config('app.url')])
#if(!empty($school['logo']) && !$school['logo']['default'])
<img src="{{ $school['logo']['url'] }}" class="logo" alt="{{ $school['logo']['alt'] }}" />
#elseif(empty($school))
<img src="https://[redacted]/public/img/logo.png" class="logo" alt="{{ config('app.name') }}" />
#else
{{ $school->name }}
#endif
#endcomponent
#endslot
<!-- END OF RELEVANT PART -->
{{-- Body --}}
{{ $slot }}
#endcomponent
3: the layout (fails)
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
</head>
<body>
<table class="wrapper" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<tr>
<td align="center">
<table class="content" width="100%" cellpadding="0" cellspacing="0" role="presentation">
<!-- THIS IS THE RELEVANT PART -->
{{ $header ?? '' }}
<!-- END OF RELEVANT PART -->
<!-- Email Body -->
<tr>
<td class="body" width="100%" cellpadding="0" cellspacing="0">
<table class="inner-body" align="center" width="570" cellpadding="0" cellspacing="0" role="presentation">
<!-- Body content -->
<tr>
<td class="content-cell">
{{ Illuminate\Mail\Markdown::parse($slot) }}
</td>
</tr>
</table>
</td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
Any idea what I'm doing wrong? The informations regarding the $school inside the message are always correct
Is it beacause I haven' used php artisan make:component to create the layout?
EDIT: removed leftover code

I've added the mail files you provided locally to test whats causing the issues. Without knowing how and what you are returning from your Mail class (return $this->markdown(...) ??), I noticed a few things about the code examples:
About the wrong shown logo:
You aren't passing the $school variable to the message blade, so your logo never could be shown and the #elseif(empty($school)) will always be true.
// message.blade.php
#component('mail::message', ['school' => $school])
Your message.blade.php contains too many #end directives, the last two # directives causing errors in the blade, remove these:
...
{{-- Body --}}
{{ $slot }}
#endcomponent
{{-- #endslot -- }} // Causes problems
{{-- #endcomponent -- }} // Causes problems
If I fix the code snippets you provided like I explained in the steps above, everything is working fine.
Please let me know if this fix your problems.

In this case, if you are sure 100% that all code lines are correct. Then it would be best if you tried to restart the queue worker on the server.

Related

render multiple inline boxes/tables in xhtml2pdf

I'm using xhtml2pdf library with Djanog to generate PDF reports. I am trying to generate a report where I'll be able to print multiple boxes for the context data.
Seems div width is not detected in xhtml2pdf, and my tables doesn't stay inlined as well.
Here's what I have done so far:
<!DOCTYPE html>
<html lang="en">
<head>
<style>
#page {
size: a4 landscape;
margin: 2cm;
}
</style>
</head>
<body>
{% for item in items %}
<table style="width: 20%; background-color: red;">
<tr style="width: 30%;">
<td style="width: 30%;">
<img class="logo" src="{{item.barcode | barcode_image}}" alt="Barcode" />
<p>{{ item.product_name }}</p> <br>
<small id="price">MRP: {{ barcode_item.price }} TK</small>
{% endif %}
</td>
</tr>
</table>
{% endfor %}
</body>
</html>
This code results:
Expected Result Format/Layout:
Is there any way to print the expected layout using xhtml2pdf?

How can i template a partial in Laravel?

I am trying to figure out how to achieve what I have in mind using laravel's blade. I want to make a reusable table template that I can extend (for example different header and body for different pages). From the research I did, I figured that templates are only for overall page structure, not partial components. So how could I achieve this? Example below
Let's say I have defined a table with some styling and draggable events and so on, I don't wat to copy and paste this table to every page just with different table body and header.
<table class="table-selectable table table-hover bg-white">
<thead class="thead-dark">
<th>Image</th>
<th>Title</th>
<th>Tags</th>
**{{SOME APPENDED HEADERS DEPENDING ON PAGE}}**
</thead>
<tbody>
#if(!empty($objects))
#foreach($objects as $object)
<tr onclick="someFunction()">
<td class="align-middle"><img class="list-image" src="some-image.jpg"></td>
<td class="align-middle"><h5>Title</h5></td>
<td class="align-middle">
Tags
</td>
**{{SOME APPENDED BODY FIELDS DEPENDING ON PAGE}}**
</tr>
#endforeach
#endif
</tbody>
</table>
Seems like a fairly simple task but I could not find a solution for this.
Blade does allow for this out of the box.
Layouts ( Docs )
<!-- Stored in resources/views/layouts/app.blade.php -->
<html>
<head>
<title>App Name - #yield('title')</title>
</head>
<body>
#section('sidebar')
This is the master sidebar.
#show
<div class="container">
#yield('content')
</div>
</body>
</html>
includes (Docs)
You can then add smaller templates to your layout using includes
#include('view.name', ['some' => 'data'])
Components (Docs)
And finally, if you want you have even more control, try components.
Note: Components are now a little more complicated than they were but are still backward compatible. So you can still define components like so:
modal.blade (Component)
<!-- Modal -->
<div
class="modal fade {{ $class ?? '' }}"
id="{{ $id }}"
tabindex="-1"
role="dialog"
aria-labelledby="{{ $id }}Title"
aria-hidden="true"
>
<div class="modal-dialog modal-dialog-centered {{ $size ?? '' }}" role="document">
<div class="modal-content shadow">
<div class="modal-header">
<h5 class="modal-title font-weight-normal" id="{{ $id }}Title">
{{ $title }}
</h5>
<button type="button" class="close close-icon" data-dismiss="modal" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
#if ($form) {{ $action }} #endif
<div class="modal-body">
{{ $body }}
</div>
<div class="modal-footer">
{{ $footer }}
</div>
#if ($form) {!! Form::close() !!} #endif
</div>
</div>
</div>
Usage
#component('components.modal', [
'id' => 'myModalID',
'class' => 'modal-info',
'form' => true
])
#slot('title')
My Modal
#endslot
#slot('action')
{!! Form::open([]) !!}
#endslot
#slot('body')
Some content
#endslot
#slot('footer')
<button type="submit" class="btn">
Submit
</button>
#endslot
#endcomponent

#yield working on home page, but not on other pages using same layout

Really scratching my head on this one. I'm hoping a fresh pair of eyes can spot my error.
I've got a section heading on each page, but the heading is only showing on home.blade.php but not other pages.
master.blade.php
<!DOCTYPE html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" />
<meta name="csrf-token" content="{{ csrf_token() }}" />
<title>#yield('title')</title>
#stack('styles')
</head>
<body class="bg-light">
<div class="container-fluid h-100">
#yield('app')
</div>
#include('sweetalert::alert')
{{ Session::forget('alert') }}
#stack('scripts')
</body>
</html>
app.blade.php
#extends('layout.master')
#prepend('styles')
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/flatpickr/dist/flatpickr.min.css">
<link rel="stylesheet" type="text/css" href="{{ URL::asset('css/overrides.css') }}" />
#endprepend
#section('app')
<div class="row">
<div class="col-12 no-padding">
#include('layout.includes.header')
</div>
</div>
<div class="row h-100">
<div class="col-12">
<!-- Begin nav/content row -->
<div class="row h-100">
<div id="sidebar-wrapper" class="visible">
#include('layout.includes.nav')
</div>
<!-- Begin main column -->
<div class="col content" style="overflow-x:auto;">
#if (Request::path() === '/')
<div class="row no-padding">
<div class="col d-none d-sm-block">
<h4>#yield('content-heading')</h4> <!-- [my #yield directive is here] -->
</div>
<div class="col flex-grow-1">
#include('layout.includes.searchform')
</div>
</div>
#endif
<div class="row no-padding inner-box shadow p-3 mb-5 bg-white rounded">
#yield('content')
</div>
</div>
<!-- END main column-->
</div>
<!-- END nav/content row-->
</div>
</div>
#endsection
#prepend('scripts')
#include('layout.js.footer-js')
#yield('form-js')
#endprepend
home.blade.php
#extends('layout.app')
#section('title', 'Asset Management')
#section('content-heading', 'View All Assets') //This works
#section('content')
<div class="table-responsive">
<table class="table table-striped text-nowrap">
<caption>Recently Added Assets</caption>
<thead>
<tr>
<th scope="col">Tag #</th>
<th scope="col">Type</th>
<th scope="col">Device</th>
<th scope="col">Serial #</th>
<th scope="col">Assigned</th>
<th scope="col">To</th>
<th scope="col">Status</th>
</tr>
</thead>
<tbody>
#foreach ($assets as $asset)
<tr>
<td>{{ $asset->asset_tag }}</td>
<td>{{ $asset->cat_name }}</td>
<td>{{ $asset->man_name }} {{ $asset->model_name }}</td>
<td>{{ $asset->serial }}</span></td>
<td>{{ \Carbon\Carbon::parse($asset->assign_date)->format('D M d, Y g:iA') }}</td>
<td>{{ $asset->name }}</td>
<td>{{ $asset->status }}</td>
</tr>
#endforeach
</tbody>
</table>
</div>
#endsection
#section('form-js')
#endsection
#push('scripts')
#endpush
My other pages are all laid out the same as home.blade.php, e.g:
#extends('layout.app')
#section('title', 'Checkout Asset')
#section('content-heading', 'Checkout Asset') //Does not output to template
#section('content')
Content here...
#endsection
#push('scripts')
#endpush
Why is <h4>#yield('content-heading')</h4> only working on home.blade.php?
The code which displays #yield('content-heading') is wrapped in:
#if (Request::path() === '/')
...
#endif
which is restricting the display to just that url.
:)

Laravel auth on existing project

I have been working on a 'laravel' project and now want to implement an authentication. I have done 'make:auth' and the folders, routes, views etc show in the project as expected.
I have added links to login and register at the top of my homepage. When either of these links are selected they try to redirect as you would expect... So clicking login is changing URL to /login, however, I am not seeing the login page content. I get the following error message:
Trying to get property of non-object
And it has highlighted <?php echo e($film->title); ?> which is on my comments page.
I don't mind if the user is able to view all the pages and content when not logged in. I am just adding auth so that I can store comments against a user.
Why is it giving me this error / how can I fix it?
Routes:
/* display list of all films*/
Route::get('/', 'FilmsController#display');
/* display film comments*/
Route::get('/{id}', 'FilmsController#comment');
Route::post('/{id}', 'FilmsController#addComment')->name('addComment');
Route::get('/delete/{id}', 'FilmsController#deleteComment')->name('deleteComment');
Route::get('/update/{id}', 'FilmsController#editComment')->name('editComment');
Route::post('/update/{id}', 'FilmsController#saveComment')->name('saveComment');
Auth::routes();
Route::get('/home', 'HomeController#index')->name('home');
Home page view:
<!doctype html>
<html lang="{{ app()->getLocale() }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Films</title>
</head>
<body>
<div class="flex-center position-ref full-height">
#if (Route::has('login'))
<div class="top-right links">
#auth
Home
#else
Login
Register
#endauth
</div>
#endif
<h1>Films</h1>
<table id="myTable">
<tr>
<th>Title</th>
<th>Director</th>
<th>Description</th>
<th>Released</th>
</tr>
#foreach ($films as $film)
<tr>
<td>
{{$film->title}}
</td>
<td>{{$film->director}}</td>
<td>{{$film->description}}</td>
<td>{{ Carbon\Carbon::parse($film->date)->format('l\\, jS \\of F Y\\, h:i A') }}</td>
</tr>
#endforeach
</body>
</html>
Comments view
<h1>{{ $film->title }}</h1>
<!--<p>{{$film->comments}}</p>-->
<table id="myTable">
<tr>
<th>Comment</th>
<th>User</th>
<th>Update</th>
<th>Delete</th>
#foreach ($film->comments as $comment)
<tr>
<td>{{$comment->body}}</td>
<td>Lorem</td>
<td>Update</td>
<td>Delete</td>
</tr>
#endforeach
</table>
<div>#include('form')</div>
The home controller and views remain as the were created by make:auth...
Home view
#extends('layouts.app')
#section('content')
<div class="container">
<div class="row">
<div class="col-md-8 col-md-offset-2">
<div class="panel panel-default">
<div class="panel-heading">Dashboard</div>
<div class="panel-body">
#if (session('status'))
<div class="alert alert-success">
{{ session('status') }}
</div>
#endif
You are logged in!
</div>
</div>
</div>
</div>
</div>
#endsection
Home controller
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('home');
}
}
Film Controller function which relates to displaying comments:
/* Displays comments for a film*/
public function comment($id)
{
$film = Film::find($id);
return view('comment', compact('film'));
}
All my other code works apart from this. I am getting this error when I just click the login/register link. I don't see the page content at all. It takes you straight to the object error.
The error is caused by this line:
<h1>{{ $film->title }}</h1>
You need to return $film with the Film object in it from the controller method that renders comments view. For example:
return view('comments', ['film' => Film::find(1)]);
Also, put these route at the end of the web.php file:
Route::get('/{id}', 'FilmsController#comment');
Route::post('/{id}', 'FilmsController#addComment')->name('addComment');

Vue.js and Laravel integration issue

Ran into a bit of a problem with combining Laravel and Vue.js to populate a table.
Essentially, I was trying to use the v-repeat property in combination with a http:get request using the vue-resources extension. The problem is that no values appear to be getting passed through by Vue - I simply get the {{first_name}} and {{email_address}} in brackets.
I can confirm that the API method that is called by the http:get request is in fact spitting out data (manually accessing the URL in the browser reveals data).
Here is the code in the routes.php file that is responsible for outputting the data:
get('api/v1_users',function()
{
return App\User::all()->toJson();
});
And here is what it spits out in the browser:
[{"email_address":"test123#gmail.com,"first_name":"John","password":"test123"}]
The Chrome console displays no errors nor warnings.
Here is my blade file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<meta name="description" content="">
<meta name="author" content="">
<link rel="icon" href="../../favicon.ico">
<title>Navbar Template for Bootstrap</title>
<!-- Bootstrap core CSS -->
<link media="all" type="text/css" rel="stylesheet" href="{{ URL::asset('css/bootstrap.min.css') }}">
<!-- Custom styles for this template -->
{!! Html::style('css/navbar.css') !!}
</head>
<body>
<div class="container">
<!-- Static navbar -->
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#navbar" aria-expanded="false" aria-controls="navbar">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="#">User Password Operations</a>
</div>
<div id="navbar" class="navbar-collapse collapse">
<ul class="nav navbar-nav">
<li class="inactive">Reset New User</li>
<li class="inactive">Pending Users</li>
</ul>
</div><!--/.nav-collapse -->
</div><!--/.container-fluid -->
</nav>
<!-- Main component for a primary marketing message or call to action -->
<div class="jumbotron">
<h1>Pending 1.0 Users</h1>
<p>A list of 1.0 users that have a change!me password as a result of this tool, and are awaiting password change.</p>
</div>
<table class="table table-bordered">
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Email</b>
</td>
<td>
<b>Select</b>
</td>
</tr>
<div id = "user">
<tr v-repeat = "user: v1_user">
<td>
#{{ first_name }}
</td>
<td>
#{{ email_address }}
</td>
<td>
<button type="button" class="btn btn-success">Revert Password To Original</button>
</td>
</tr>
</div>
</table>
<div class="jumbotron">
<h1>Pending 2.0 Users</h1>
<p>A list of 2.0 users that have a change!me password as a result of this tool, and are awaiting password change.</p>
</div>
<table class="table table-bordered">
<tr>
<td>
<b>Name</b>
</td>
<td>
<b>Email</b>
</td>
<td>
<b>Select</b>
</td>
</tr>
<div>
<tr v-repeat = "user: v1_user">
<td>
#{{user.first_name}}
</td>
<td>
#{{user.email_address}}
</td>
<td>
<button type="button" class="btn btn-success" v-on= "click: onClick">Revert Password To Original</button>
</td>
</tr>
</div>
</table>
</div> <!-- /container -->
<!-- Bootstrap core JavaScript
================================================== -->
<!-- Placed at the end of the document so the pages load faster -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.3/jquery.min.js"></script>
<!-- Vue.js file REP -->
<script src="/js/vue.js"></script>
<script src="/js/vue-resource.min.js"></script>
<!-- Main Vue file-->
<script src="/js/main.js"></script>
</body>
</html>
Here is the accompanying javascript file with the Vue.js code: (main.js)
new Vue({
el: "#user",
data:
{
v1_user:[],
},
ready : function()
{
this.fetchV1IntermediaryUsers();
},
methods:
{
fetchV1IntermediaryUsers: function() {
this.$http.get('/api/v1_users',function(v1users) {
this.$set('v1_user',v1users);
});
}
}
});
You have multiple DIV's with the same ID's. ID's in HTML must be unique. When you start a VUE instance you bind it to an element, in this case which is in your code twice. Remove the ID's and add an ID to the <Body> tag, then check your code.

Resources