In my education resources controller system, we have to prepare progress reports for student.To get these reports as a pdf I used Laravel dom-pdf.
code of pdfGeneratorController
<?php
namespace App\Http\Controllers;
use Illuminate\Support\Facades\DB;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\User;
use App\Subject;
use PDF;
class pdfGenerator extends Controller
{
public function reportPdf()
{
$users = DB::table('users')->get();
$subjects = DB::table('subjects')->get();
$pdf = PDF::loadview('reports', ['users' => $users],['subjects' => $subjects]);
// $pdf = PDF::loadview('reports', ['subjects' => $subjects]);
return $pdf->download('report.pdf');
}
public function report()
{
// $users = DB::table('users')->get();
$users = DB::table('users')
->join('subjects','users.id','=','subjects.user_id')
->join('marks','subjects.user_id','=','subjects.user_id')
->select('users.*','subjects.subject','marks.marks')
->get();
//$subject = Subject::all();
// return $subject;
return view('reports', ['users' => $users]);
}
}
codes of reports.blade.php
<!DOCTYPE html>
<html>
<head>
<style>
table {
font-family: arial, sans-serif;
border-collapse: collapse;
width: 100%;
}
td, th {
border: 1px solid #dddddd;
text-align: left;
padding: 8px;
}
tr:nth-child(even) {
background-color: #dddddd;
}
</style>
</head>
<body>
<h1><a href="{{url('/pdfs')}}" > Download pdf</a></h1>
<table>
<caption>Student Details</caption>
<tr>
<td>Name</td>
<td> lname </td>
<td>subject</td>
<td>marks</td>
</tr>
#foreach($users as $user)
<tr>
<td>{{ $user->name}}</td>
<td>{{ $user->lname}}</td>
<td>{{ $user->subject}}</td>
<td>{{ $user->marks}}</td>
#endforeach
</tr>
</table>
</body>
</html>
When I click reports link it shows all the relevant data webpage. but when i click print pdf link it gives a error.the error of this time is ErrorException
Undefined property: stdClass::$subjects (View: E:\nimnayawebsite\resources\views\reports.blade.php)
You are passing two array with comma separated value, pass it making one array.
Change this line-
$pdf = PDF::loadview('reports', ['users' => $users],['subjects' => $subjects]);
To this-
$pdf = PDF::loadview('reports', ['users' => $users,'subjects' => $subjects]);
You're trying yo use $user->subject in the view. Since report() method works for you with the same view, change this:
$users = DB::table('users')->get();
$subjects = DB::table('subjects')->get();
To:
$users = DB::table('users')
->join('subjects','users.id','=','subjects.user_id')
->join('marks','subjects.user_id','=','subjects.user_id')
->select('users.*','subjects.subject','marks.marks')
->get();
Related
I am using laravel framework. here in my code HTML table view is ok.But when i am converting the same to pdf using mpdf, the table is displaying without any borders. i am using css in same html. no external style sheets are included
my code is here
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">
<style>
td{
border-top: 1px dotted black;
border-bottom: 1px dotted black;
border-left: 1px dotted black;
border-right: 1px dotted black;
}
table {
margin-left: 5px;
border: 1px solid black;
}
td {
border: 1px solid black;
}
</style>
<title>Document</title>
</head>
<body>
<table class="pdf">
<thead>
<tr>
<th>Name</th>
<th>Phone</th>
<th>Password</th>
<th>Role ID</th>
</tr>
</thead>
<tbody style="font-size: 14px;">
#foreach ($users as $user)
<tr>
<td>{{ $user->name }}</td>
<td>{{ $user->mobile }}</td>
<td style="width: 20%;">{{ $user->password }}</td>
<td>{{ $user->department_id }}</td>
<td>{{ $user->i }}</td>
</tr>
#endforeach
</tbody>
</table>
<script src="https://cdn.jsdelivr.net/npm/#popperjs/core#2.9.3/dist/umd/popper.min.js"
integrity="sha384-eMNCOe7tC1doHpGoWe/6oMVemdAVTMs2xqW4mwXrXsW0L84Iytr2wi5v2QjrP/xp" crossorigin="anonymous">
</script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.1.0/dist/js/bootstrap.min.js"
integrity="sha384-cn7l7gDp0eyniUwwAZgrzD06kc/tftFf19TOAs2zVinnD/C7E91j9yyk5//jjpt/" crossorigin="anonymous">
</script>
</body>
</html>
Here is my controller
<?php
namespace App\Http\Controllers;
use App\Models\User;
use Illuminate\Http\Request;
use Mpdf\Mpdf;
use Illuminate\Support\Facades\View;
// use phpDocumentor\Reflection\PseudoTypes\False_;
class PdfController extends Controller
{
public function index()
{
$users = User::all();
return view('pdf',compact('users'));
}
public function generate()
{
require_once base_path('vendor/autoload.php');
$defaultConfig = (new \Mpdf\Config\ConfigVariables())->getDefaults();
$fontDirs = $defaultConfig['fontDir'];
$defaultFontConfig = (new \Mpdf\Config\FontVariables())->getDefaults();
$fontData = $defaultFontConfig['fontdata'];
$custom_font_path = storage_path().'\fonts';
// dd($custom_font_path);
$mpdf = new \Mpdf\Mpdf([
'fontDir' => array_merge($fontDirs, [
$custom_font_path,
]),
'fontdata' => $fontData + [
'gayathri' => [
'R' => 'Gayathri-Regular.ttf',
'useOTL' => 0xFF,
]
],
'default_font' => 'gayathri'
]);
$mpdf->SetFont('dejavusanscondensed');
$mpdf->simpleTables=true;
// $mpdf->packTableData=true;
// $mpdf->keep_table_proportions=TRUE;
// $mpdf->shrink_tables_to_fit=1;
// $users = User::all();
// foreach($users as $user)
// {
// $mpdf->WriteHTML('<p style="font-size:28px;">'. $user->name .'</p> ');
// }
// calculate two numbers
$users = User::all();
$view = View::make('pdf', compact('users'));
$mpdf->WriteHTML($view);
$mpdf->Output();
}
}
In the generated pdf there is no borders but cell divisions and other layouts are ok, how to include borders for the entire table.( including cells, colums etc)
Don't use the style tag. Try to use stylesheet instead:
$stylesheet = file_get_contents('css/style.css');
//CSS
$mpdf->WriteHTML($stylesheet, \Mpdf\HTMLParserMode::HEADER_CSS);//This is css/style only and no body/html/text
//BODY
$mpdf->WriteHTML($html,\Mpdf\HTMLParserMode::HTML_BODY);//This is html content, without <head> information.
Check out this documentation.
Until now that I am dropping some lines here, there is still something wrong with MPDF when dealing with table borders.
When you style <td> and add border there, what you can see in the output is just border left and border right, and no border top and border down. For me, so as to bypass the problem, I styled both and to get all the borders working, that is top, bottom, right, and left. I just shared my solution in case someone would find it useful.
table td, table th, table tr {
border: 1px solid #c9c9c9 !important
}
why is my queue job timing out? I am using database as a driver I tried the following:
class PdfGenerator implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
protected $userData;
protected $filename;
protected $path;
public $timeout = 1200;
/**
* Create a new job instance.
*
* #return void
*/
public function __construct($userData, $filename)
{
//
$this->userData = $userData;
$this->filename = $filename;
$this->path = \public_path('\\pdfs\\'.$this->filename.'.pdf');
}
/**
* Execute the job.
*
* #return void
*/
public function handle()
{
$pdf = App::make('snappy.pdf.wrapper');
$footer = \view('supporting.footer')->render();
$header = \view('supporting.header')->render();
//$userData = \collect([$this->userData[1]]);
$pdf->loadView('order_clean', ['users' => $this->userData])
->setOption('margin-top', '20mm')
->setOption('margin-bottom', '20mm')
->setOption('minimum-font-size', 25)
->setOption('header-html', $header)
->setOption('footer-html', $footer);
$pdf->save($this->path);
}
}
php artisan queue:work --timeout=1200
php artisan queue:listen --timeout=0
yet my queue job still fails due to timeout of 60s according to the logs because the symfony process timed out. I am not using supervisor yet, just trying out how the queue works from the console
edit:: controller code + blade code
controller code:
class OrderController extends Controller
{
public function renderPDF()
{
$user_data = $this->getUserData();
$filename = 'test '.\now()->timestamp;
//no timeouts here
//if not ran on queue and with set_time_limit, takes around 70s
//at current data size
$this->dispatch(new PdfGenerator($user_data,$filename));
//view returns successfully
return \view('test.test', ['filename'=>$filename]);
}
}
Blade file:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Order Layout</title>
<style>
*{
font-family: cursive;
}
.wrapper {
display: block;
}
.invoice {
display: block;
width: 80%;
margin: 0 auto;
margin-top: 10px;
padding-top: 10px;
padding-bottom: 10px;
background: #d3d3d3;
page-break-inside: avoid !important;
padding-left: 20px;
}
.order-items {
padding-left: 100px;
}
.table {
width: 90%;
align-self: center;
border: 1px solid black;
orphans: 15;
}
.table>* {
text-align: center;
}
</style>
</head>
<body>
<main class="wrapper">
#foreach ($users as $user)
#php
$orders = $user->orders //just for renaming
#endphp
#foreach ($orders as $order)
<div class="invoice">
#php
$sum=0;
#endphp
<h2>{{$user->name}}: {{$order->id}}</h2>
<div class="order-items">
<table class="table" border="1">
<thead>
<tr>
<th>Product Name</th>
<th>Unit Price</th>
<th>Qty</th>
<th>subtotal</th>
</tr>
</thead>
<tbody>
#foreach ($order->products as $product)
<tr>
<th>
{{$product->name}}<br>
{{$product->name}}<br>
{{$product->name}}<br>
{{$product->name}}<br>
</th>
<td>{{$product->unit_price}}</td>
<td>{{$product->pivot->quantity}}</td>
#php
$sum+= $product->pivot->quantity*$product->unit_price
#endphp
<td>{{$product->pivot->quantity*$product->unit_price}}</td>
</tr>
#endforeach
</tbody>
<tfoot>
<tr>
<th colspan="3">Total:</th>
<td>{{$sum}}</td>
</tr>
</tfoot>
</table>
</div>
</div>
#endforeach
#endforeach
</main>
</body>
</html>
If you want to be able to set the timeouts you should make sure you have the pcntl PHP extension installed and enabled.
"The pcntl PHP extension must be installed in order to specify job timeouts."
Laravel 8.x Docs - Queues - Dispatching Jobs - Specifying Max Job Attempts / Timeout Values - Timeout
I am trying to send an HTML template to MailTrap using this method
public function send($result_id)
{
$result = Result::whereHas('user', function ($query) {
$query->whereId(auth()->id());
})->findOrFail($result_id);
\Mail::to('test#eam.com')->send(new ResultMail);
return view('client.result', compact('result'))->withStatus('Your test result has been sent successfully!');
}
with the result.blade.file
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Test No. {{ $result->id }}</title>
<link href="{{ asset('css/app.css') }}" rel="stylesheet" type="text/css" />
<style type="text/css">
html {
margin: 0;
}
body {
background-color: #FFFFFF;
font-size: 10px;
margin: 36pt;
}
</style>
</head>
<body>
<p class="mt-5">Total points: {{ $result->total_points }} points</p>
<table class="table table-bordered">
<thead>
<tr>
<th>Question Text</th>
<th>Points</th>
</tr>
</thead>
<tbody>
#foreach($result->questions as $question)
<tr>
<td>{{ $question->question_text }}</td>
<td>{{ $question->pivot->points }}</td>
</tr>
#endforeach
</tbody>
</table>
</body>
</html>
but I'm get an error
Undefined variable: result (View: C:\Users\USER\Documents\Laravel-Test-Result-PDF-master\Laravel-Test-Result-PDF-master\resources\views\client\result.blade.php)
Well, as far as I know, you need to have Mailable class and from the mailable class, you need to return the view and pass the data there.
You'r mailable class should
class ResultMail extends Mailable
{
use Queueable, SerializesModels;
public $result;
/**
* Create a new message instance.
*
*/
public function __construct($result)
{
$this->result = $result;
}
/**
* Build the message.
*
* #return $this
*/
public function build()
{
return $this->view('client.result');
}
}
Should be something like this.And then you need to pass the data to ResultMail
\Mail::to('test#eam.com')->send(new ResultMail($result));
In my laravel project am taking data from multiple tables and showing it in view.
I have uploaded the picture of current output.
I have multiple services in one location id, but I want to show only one location id and their corresponding services in right side.
Following is my code in controller
public function showClinicLocations($id)
{
$clinic = Clinic::find($id);
$locations = Location::where('clinicID', $id)->get();
$locationservices = Service::select('services.serviceName as servicename','locations.locationID as locid')
->join('location_services', 'location_services.serviceID', '=', 'services.serviceID')
->join('locations', 'locations.locationID', '=', 'location_services.locationID')
->join('clinics', 'clinics.clinicID', '=', 'locations.clinicID')
->where('clinics.clinicID','=',$id)
->get();
return view('clinic.locations')->with(['locations' => $locations ,'clinic'=>$clinic , 'services'=> $locationservices]);
}
Following is the code in view page
<table>
<thead>
<tr>
<th>Location Name</th>
<th>Services</th>
</tr>
</thead>
<tbody>
#foreach($services as $service)
<tr>
<td>{!! $service->locid !!}</td>
<td>{!! $service->servicename !!}</td>
</tr>
#endforeach
</tbody>
</table>
I want to show only one unique locid and their services in one row, why am not getting like that
And my expected output is in given image
Currently you are retrieving from database as the output you show, you can achieve what you want by just changing your blade template like this:
<tbody>
#foreach($locations as $location)
<tr>
<?php
$first = true;
foreach($services as $service){
echo('<tr>')
if($service->locid == $location->locationID ){
if($first){
echo('<td class="first">' . $location->locationID . '</td>')
$first=false;
}
else{
echo('<td class="second"></td>')
}
echo('<td>'.$service->servicename.'</td>')
echo('<td><button id="btn_'.$service->serviceID.'">Delete</button></td>')
}
echo('</tr>')
}
?>
</td>
</tr>
#endforeach
</tbody>
To erase the lines, you'll have to add some CSS:
.first{
border-top: 1px solid black;
border-right: 1px solid black;
border-left: 1px solid black;
}
.second{
border-right: 1px solid black;
border-left: 1px solid black;
}
I hope this helps you.
As of now your query result will be separated because you didn't group them.
Here's example
$locationservices = Service::select(DB::raw("GROUP_CONCAT(services.serviceName SEPERATOR ',') as servicename, locations.locationID as locid")
->join('location_services', 'location_services.serviceID', '=', 'services.serviceID')
->join('locations', 'locations.locationID', '=', 'location_services.locationID')
->join('clinics', 'clinics.clinicID', '=', 'locations.clinicID')
->where('clinics.clinicID','=',$id)
->groupBy('locations.locationID')
->get();
If group by has an error just add the servicename
->groupBy('locations.locationID', 'services.serviceName')
then the view is just the same.
You can change the seperator anything you want.
Hope it helps.
I don't know how to do a edit and delete function in codeigniter.. I really need it for the admin side of my system.. I really need help.. I want to delete the id in my table named user_acc and edit the whole column
Model:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Mod_admin extends CI_Model{
function __construct()
{
parent::__construct();
}
public function user_acc(){
$this->db->select('*');
$this->db->from('user_acc');
$query = $this->db->get();
return $query->result();
}
public function delete()
{
$this->db->where('id');
$this->db->delete();
}
}
Admin:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class Admin extends CI_Controller {
public function __construct()
{
parent::__construct();
$this->load->helper('url');
$this->load->Model('Mod_admin');
}
public function manageuser(){
$this->load->view('template/adminhead');
$data['user_acc'] = $this->Mod_admin->user_acc();
$this->load->view('manageuser', $data);
}
public function delete_product() {
$this->Mod_admin->delete();
$this->session->set_flashdata('message', '<p>Product were successfully deleted!</p>');
redirect('manageuser');
}
}
View:
<html>
<title>Manage User</title>
<body>
<style>
.shit{
border: 1px solid;
border-collapse: collapse;
}
.shit td{
border: 1px solid;
border-collapse: collapse;
padding: 7px;
}
.shit td tr{
border: 1px solid;
}
.shit td th{
border: 1px solid;
}
</style>
<div id="container">
<table class="shit">
<tr>
<th><strong>ID</strong></th>
<th><strong>Firstname</strong></th>
<th><strong>Lastname</strong></th>
<th><strong>Username</strong></th>
<th><strong>Password</strong></th>
<th><strong>E-mail</strong></th>
<th><strong>Contact</strong></th>
<th><strong>Edit</strong></th>
<th><strong>Delete</strong></th>
</tr>
<?php
foreach($user_acc as $row){
echo
'<tr>
<td>'.$row->id.'</td>
<td>'.$row->firstname.'</td>
<td>'.$row->lastname.'</td>
<td>'.$row->username.'</td>
<td>'.$row->password.'</td>
<td>'.$row->email.'</td>
<td>'.$row->contact.'</td>
<td>'.''.'Edit'.'</td>
<td>'.''.'Delete'.'</td>
</tr>';
}
?>
</table>
</div>
</body>
</html>]
How View looks like
Please help me to edit and delete users thanks
For updating
In controller:
$result = array( 'column1'=>$val1,'column2'=>$val2,'column3'=>$val3);
$this->model_name->updateEvent( $id , $result );
In model:
public function updateEvent($id, $result){
$this->db->where('db_table_column', $id);
$this->db->update('table_name', $result);
}
For deleting
In controller:
$this->model_name->deleteEvent( $id );
In model:
public function deleteEvent( $id )
{
$this->db->where('db_table_column', $id);
$this->db->delete('table_name');
}