I am using the fpdf library for my laravel project. I create a class for the header and footer function. Then call thess functions on my pdf controller. I encounter this error "FPDF error: No page has been added yet" and I have no idea where this error came from. Can you teach me on how to fix this bug/error. Thanks in advance.
Codes from my controller
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Codedge\Fpdf\Fpdf\Fpdf;
use App\Personnel;
use App\Classes\PDFClass;
class PFTReportController extends Controller
{
public function postPFTReport(Request $request)
{
$pdf = new FPDF();
$pdf->AddPage('P', 'A4');
$pdf->Ln(4);
$pdf->SetFont('Arial', '', 12);
// Call the header for this report
$pdfClass = new PDFClass();
$header = $pdfClass->Header();
$pdf->Cell(0, 4, 'Sample Report', 0, 1, 'C');
$pdf->Ln(2);
$pdf->Output();
exit;
}
}
Code of the class
namespace App\Classes;
use Codedge\Fpdf\Fpdf\Fpdf;
class PDFClass extends Fpdf
{
protected $B = 0;
protected $I = 0;
protected $U = 0;
protected $HREF = '';
// Page header
function Header()
{
$this->SetFont('Arial', '', 11);
$this->Cell(0, 2, 'Line 1', 0, 1, 'C');
$this->Cell(0, 8, 'Line 2', 0, 1, 'C');
$this->SetFont('Arial', 'B', 12);
$this->Cell(0, 1, 'Line 3', 0, 1, 'C');
$this->Cell(0, 8, 'Line 4', 0, 1, 'C');
$this->SetFont('Arial', '', 12);
$this->Cell(0, 1, 'Line 5', 0, 1, 'C');
$this->Ln(8);
}
}
You create 2 class instances. The first is FPDF where you add a page:
$pdf = new FPDF();
$pdf->AddPage('P', 'A4');
$pdf->Ln(4);
$pdf->SetFont('Arial', '', 12);
...then you create a new one and simply call your Header() method manually:
$pdfClass = new PDFClass();
$header = $pdfClass->Header();
This doesn't make sense and at this point the error is thrown, because you call several methods in Header() which should output content to a page but you didn't added one before.
You should only use PDFClass and you also should not call the Header() method manually because it is called internally automatically.
public function postPFTReport(Request $request)
{
$pdf = new PDFClass();
$pdf->AddPage('P', 'A4'); // NOW THE HEADER() METHOD IS INVOKED AUTOMATICALLY IN THIS CALL
$pdf->Ln(4);
$pdf->SetFont('Arial', '', 12);
$pdf->Cell(0, 4, 'Sample Report', 0, 1, 'C');
$pdf->Ln(2);
$pdf->Output();
exit;
}
Related
I just want to make the row of datas will rendered after headings
This's the result that i want
this what i want
But i only get this result
this i get
I already using startRow and set to 7, but nothing change
I have 6 row of heading, so how to render/display the data after headings, and i already return another collection with another model, but the result is same there's nothing change, the data keep displayed from first row
<?php
namespace App\Exports;
Importing Models...
use Maatwebsite\Excel\Concerns\FromCollection;
use Maatwebsite\Excel\Concerns\WithHeadings;
use Maatwebsite\Excel\Concerns\WithColumnWidths;
use Maatwebsite\Excel\Concerns\WithStyles;
use PhpOffice\PhpSpreadsheet\Worksheet\Worksheet;
use Maatwebsite\Excel\Concerns\RegistersEventListeners;
use Maatwebsite\Excel\Events\AfterSheet;
use Maatwebsite\Excel\Concerns\WithEvents;
class TahapSeleksiExport implements FromCollection, WithHeadings, WithColumnWidths, WithStyles, WithEvents
{
use RegistersEventListeners;
protected $id;
function __construct($id) {
$this->id = $id;
}
/**
* #return \Illuminate\Support\Collection
*/
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
return Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
return SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
}
}
public function columnWidths(): array
{
return [
'A' => 15,
'B' => 40,
'C' => 15,
'D' => 15,
'E' => 25,
'F' => 12,
];
}
public function styles(Worksheet $sheet)
{
$sheet->getStyle(2)->getFont()->setBold(true);
$sheet->mergeCells('A2:G2');
$sheet->mergeCells('A3:G3');
$sheet->mergeCells('A4:G4');
}
public static function afterSheet(AfterSheet $event)
{
$sheet = $event->sheet->getDelegate();
$sheet->getStyle(2)->getFont()->setSize(16);
$sheet->getStyle(3)->getFont()->setSize(14);
$sheet->getStyle(4)->getFont()->setSize(14);
$sheet->getStyle('A6:G6')->getFont()
->setBold(true)
->getColor()->setRGB('ffffff');
$sheet->getStyle('A6:G6')->getFill()
->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
->getStartColor()->setARGB('2041BB');
}
public function headings():array
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
return [ // PER ROW HEADINGNYA
[], [$tahap->nama], ['Seleksi Alumni'], ['BKK SMKN 1 Kota Bekasi'],[],[
'ID Pelamar',
'Nama',
'Jurusan',
'Angkatan',
'Tanggal Submit',
'Nilai',
'Lulus',
]
];
}
}
The easy solution is to add an empty array of data to the collection. The solution is not idle but I think it can works. Try this:
public function collection()
{
$tahap = Tahap::where('id_tahap', $this->id)->first();
$PelamarData = new Collection();
if ($tahap->status == '0') {
if ($tahap->tahap_ke == '1') {
$PelamarData = Pelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->get();
}else{
$PelamarData = SeleksiPelamar::select('pelamar.id_pelamar', 'alm.nama', 'jur.akronim', 'ang.angkatan', 'pelamar.tanggal_kirim')
->where('lowongankerja_id', $tahap->lowongankerja_id)
->join('pelamar', 'pelamar.id_pelamar', '=','seleksi_pelamar.pelamar_id')
->join('alumni_mendaftar_pelamar as almPel', 'almPel.pelamar_id', '=','pelamar.id_pelamar')
->join('alumni as alm', 'almPel.alumni_id', '=','alm.id_alumni')
->join('jurusan as jur', 'alm.jurusan_id', '=','jur.id_jurusan')
->join('angkatan as ang', 'alm.angkatan_id', '=','ang.id_angkatan')
->orderBy('pelamar.tanggal_kirim')
->orderBy('jur.akronim')
->orderBy('ang.angkatan', 'DESC')
->where('keterangan', '1')->whereHas('tahap', function ($tahaps) use ($tahap) {
$tahaps->where('lowongankerja_id', $tahap->lowongankerja_id)->where('tahap_ke', $tahap->tahap_ke - 1);
})->get();
}
//Add empty array data to skip the first 7 rows
foreach (range(1, 7) as $item)
{
$PelamarData->prepend([]);
}
return $PelamarData;
}
}
The built in behavior for flashing back validation errors in Laravel does not seem to be working for my use case.
I have a (React) form that posts it's data via fetch API using this method, which reloads or redirects the page with (hopefully) any session data after the response is returned:
fetch(props.register_route, {
method: 'POST',
headers: {
'X-CSRF-Token': props.csrf,
},
body: data,
})
.then((result) => {
return result.json();
})
.then((result) => {
console.log(result);
window.location.href = result.url;
},
(error) => {
console.log(error);
});
In my controller, I validate this data but if I structure it as follows, the errors are not available as $errors in the resulting page
if ($validator->fails()) {
return redirect()->back()->withErrors($validator);
}
However if I manually flash the errors to the session and return a url instead of a redirect, suddenly the behavior works.
if ($validator->fails()) {
Session::flash('errors', $validator->errors());
return response->json([
'url' => route('register'),
], Response::HTTP_NOT_ACCEPTABLE);
}
I feel as if I must be doing something incorrectly here to have to use this workaround. I could also manually send the errors back in the response, which may be the right way to structure things in the long run.
when you are calling api from javascript or front end applications like Reactjs,Angular,android etc.. .So it expect return result should be in json format so it should be like
if ($validator->fails()) {
return response()->json( $validator->errors(),422);
}
if you not calling Method from direct laravel blade then pass response in JOSN Format.
like
https://laravel.com/docs/8.x/responses#json-responses
Or
make one ResponseManager File
<?PHP
namespace App\Libraries\utils;
class ResponseManager {
public static $response = array('flag' => true, 'data' => '', 'message' => '', 'code' => 01,);
public static function getError($data = '', $code = 10, $message = '', $flag = false) {
self::$response['flag'] = $flag;
self::$response['code'] = $code;
self::$response['data'] = $data;
self::$response['message'] = $message;
return self::$response;
}
public static function getResult($data = '', $code = 10, $message = '', $flag = true) {
self::$response['flag'] = $flag;
self::$response['code'] = $code;
self::$response['data'] = $data;
self::$response['message'] = $message;
return self::$response;
}}
Define in config/app.php
//custom class
'ResponseManager' => App\Libraries\utils\ResponseManager::class,
and then use in whole project
Error Message Like
if ($validation->fails()) {
$message = $validation->messages()->first();
return Response()->json(ResponseManager::getError('', 1, $message));
}
Success Message Like
return Response()->json(ResponseManager::getResult(null, 10, "Success"));
My controller to generate pdf is as folloe
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
class C_test extends CI_Controller {
function __construct()
{
parent::__construct();
$this->load->library("Pdf");
}
public function create_pdf() {
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT, true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor('Vijay Kumar');
$pdf->SetTitle('TCPDF Example 001');
$pdf->SetSubject('TCPDF Tutorial');
$pdf->SetKeywords('TCPDF, PDF, example, test, guide');
set default header data
$pdf->SetHeaderData(PDF_HEADER_LOGO, PDF_HEADER_LOGO_WIDTH, PDF_HEADER_TITLE.' 001', PDF_HEADER_STRING, array(0,64,255), array(0,64,128));
$pdf->setFooterData(array(0,64,0), array(0,64,128));
// set header and footer fonts
$pdf->setHeaderFont(Array(PDF_FONT_NAME_MAIN, '', PDF_FONT_SIZE_MAIN));
$pdf->setFooterFont(Array(PDF_FONT_NAME_DATA, '', PDF_FONT_SIZE_DATA));
// set default monospaced font
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
// set margins
$pdf->SetMargins(PDF_MARGIN_LEFT, PDF_MARGIN_TOP, PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
// set auto page breaks
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
// set image scale factor
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
// set some language-dependent strings (optional)
if (#file_exists(dirname(__FILE__).'/lang/eng.php')) {
require_once(dirname(__FILE__).'/lang/eng.php');
$pdf->setLanguageArray($l);
}
// set default font subsetting mode
$pdf->setFontSubsetting(true);
$pdf->SetFont('dejavusans', '', 14, '', true);
$pdf->AddPage();
// set text shadow effect
$pdf->setTextShadow(array('enabled'=>true, 'depth_w'=>0.2, 'depth_h'=>0.2, 'color'=>array(196,196,196), 'opacity'=>1, 'blend_mode'=>'Normal'));
// Set some content to print
$html = <<<EOD
<h1>Welcome to pdf gen</h1>
EOD;
// Print text using writeHTMLCell()
$pdf->writeHTMLCell(0, 0, '', '', $html, 0, 1, 0, true, '', true);
$pdf->Output('example_001.pdf', 'I');
}
}
pdf.php library
<?php
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
require_once dirname(__FILE__) . '/tcpdf/tcpdf.php';
class Pdf extends TCPDF
{
function __construct()
{
parent::__construct();
}
}
I want to generate a pdf with custom header and footer, header is image and footer is dynamic name and need page number
In controller how to do this to work with custom pdf header and footer
You need extend TCPDF in order to use custom header and footer
class PDF extends TCPDF {
//Page header
public function Header() {
// Logo
$image_file = K_PATH_IMAGES.'logo_example.jpg';
$this->Image($image_file, 10, 10, 15, '', 'JPG', '', 'T', false, 300, '', false, false, 0, false, false, false);
// Set font
$this->SetFont('helvetica', 'B', 20);
// Title
$this->Cell(0, 15, '<< TCPDF Example 003 >>', 0, false, 'C', 0, '', 0, false, 'M', 'M');
}
// Page footer
public function Footer() {
// Position at 15 mm from bottom
$this->SetY(-15);
// Set font
$this->SetFont('helvetica', 'I', 8);
// Page number
$this->Cell(0, 10, 'Page '.$this->getAliasNumPage().'/'.$this->getAliasNbPages(), 0, false, 'C', 0, '', 0, false, 'T', 'M');
}
}
Even I did like this and got my result.
reference: https://tcpdf.org/examples/example_003/
I want to display multiple images in a gridviews single row. For example: I have table A, Table B and table C.
Table A has my_id.
In Table B my_id is the foreign key. Along with my_id it has c_id.
Table C has c_id which is in reference in Table B.
Table C also has a filepath to display images.
in Table A i have my_id as follows:
1, 2, 3, 4, 5, 6.
In Table B i have my_id as follows.
1 ,1 ,1 ,2 ,3, 3.
In Table B i also have c_id as follows.
1, 2, 3, 4, 5, 6.
In table C my c_id's are:
1, 2, 3, 4, 5, 6. and these id's have filepath associated with each of them. They are different images.
Now my gridview should display 3 different images for my_id because of the foreign key constraints. but it displays only 1 image.
My code is below:
In my model
public function getPictogramsID()
{
$pictogramsID = SdsrefGhsPictograms::find()->where(['sdsref_id' => $this->sdsref_id])->all();
foreach ($pictogramsID as $picID){
return $picID->pictogram_id;
}
}
public function getPictogramPath()
{
$pictogramsID = GhsPictogram::find()->where(['pictogram_id' => $this->getPictogramsID()])->all();
foreach ($pictogramsID as $picID){
$pic = $picID->pictogram_filepath;
}
return $pic;
}
public function getPictogramUrl()
{
//var_dump($this->getPictogramPath()); exit();
return \Yii::$app->request->BaseUrl.'/web'.$this->getPictogramPath() ;
}
my index file grid view image code
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
return Html::img($data->getPictogramUrl(), ['alt'=>'myImage','width'=>'20','height'=>'30']);
},
],
I am also trying to add a bootstrap tool tip to this.. tool tip is displaying successfully but I think the looping is not not done in a correct way so it is repeating my images.
here is my updated gridview code.
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
$images = '';
// append all images
foreach($data->getPictogramName() as $name)
foreach ($data->getPictogramUrl() as $url)
$images = $images.Html::img($url,['alt'=>'','width'=>'30','height'=>'30', 'data-toggle'=>'tooltip','data-placement'=>'left','title' => $name ,'style'=>'cursor:default;']);
return $images;
}
],
You have few logical errors in model and grid view. In all these areas you are dealing with one item instead of three.
In your model
public function getPictogramsID()
{
$ids = [];
$pictogramsID = SdsrefGhsPictograms::find()->where(['sdsref_id' => $this->sdsref_id])->all();
foreach ($pictogramsID as $picID){
$ids[] = $picID->pictogram_id;
}
return $ids;// returning all three ids
}
public function getPictogramPath()
{
$pic = [];
$pictogramsID = GhsPictogram::find()->where(['pictogram_id' => $this->getPictogramsID()])->all();
foreach ($pictogramsID as $picID){
$pic[] = $picID->pictogram_filepath;
}
return $pic;
}
public function getPictogramUrl()
{
$url = [];
foreach($this->getPictogramPath() as $path):
$url[] = \Yii::$app->request->BaseUrl.'/web'.$path;
endforeach;
return $url; // returning al urls
}
Now in you view loop over all urls and append images with each url
[
'label' => 'Hazards',
'format' => 'raw',
'value' => function ($data) {
$images = '';
// append all images
foreach($data->getPictogramUrl() as $url):
$images = $images.Html::img($url, ['alt'=>'myImage','width'=>'20','height'=>'30']);
endforach;
return $images;
},
],
I am using Joomla 2.5.11 . I have a php file stored in the /public_html/joomtest/components/com_jumi/files which is pasted below.
I have a PHP form which is stored in the same location i.e /public_html/joomtest/components/com_jumi/files.
I want the PHP form to call the PHP script so that an article is created in Joomla. But whenever the PHP script is called, I receive the below error
Fatal error: Class 'JTable' not found
and the line on which Joomla throws error is
$table = JTable::getInstance('Content', 'JTable', array());
PHP script
<?php
$table = JTable::getInstance('Content', 'JTable', array());
$data = array(
'catid' => 8,
'title' => 'SOME TITLE',
'introtext' => 'SOME TEXT',
'fulltext' => 'SOME TEXT',
'state' => 0,
);
if (!$table->bind($data))
{
$this->setError($table->getError());
return false;
}
if (!$table->check())
{
$this->setError($table->getError());
return false;
}
if (!$table->store())
{
$this->setError($table->getError());
return false;
}
?>
</body>
</html>
I tried putting in
require_once('/libraries/joomla/database/table.php');
but this again didnt work. Please help.
You need to define path of table file you want to use. Use the following code for include the specific table. For example:
JTable::addIncludePath(JPATH_SITE.DS.'components'.DS.'com_content'.DS.'tables');
And then call your table like below:
$con_table = JTable::getInstance('Content', 'JTable', array());
Hope this will work. Good Luck.