I need to generate pdf from my view, Im using kartik mPDF,
Controller :
public function actionInvoicesPrint()
{
$pdf = new Pdf([
'mode' => Pdf::MODE_CORE, // leaner size using standard fonts
'content' => $this->renderPartial('view', ['model' => $model, 'mode' => Pdf::MODE_CORE,
'format'=> Pdf::FORMAT_A4,
'orientation'=> Pdf::ORIENT_POTRAIT,
'destination'=> Pdf::DEST_BROWSER]),
]);
return $pdf->render();
}
Getting error Undefined variable: model. I tried as shown above but getting same error.
View:
public function actionView($id)
{
$searchModel = new InvoicesSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$data = Invoices::findOne($id);
return $this->render('view', [
'model' => $this->findModel($id),
'dataProvider' => $dataProvider,
'searchModel' => $searchModel,
'data' => $data,
]);
}
In your actionInvocePrint you don't have a $model assigned
below is a sample of a my working pdf (kartik mPDF like your )
$model = $this->findModel($id);
// get your HTML raw content without any layouts or scripts
//$this->layout = 'pdfmain';
$content = $this->renderPartial('_mpdf_report_scheda', [
'model' => $model,
'imglink' => $imglink,
]);
if ($print ) {
$setJS = 'this.print();';
}
else {
$setJS ='';
}
// setup kartik\mpdf\Pdf component
$pdf = new Pdf([
// set to use core fonts only
'mode' => Pdf::MODE_BLANK,
// A4 paper format
'format' => Pdf::FORMAT_A4,
// portrait orientation
'orientation' => Pdf::ORIENT_PORTRAIT,
// stream to browser inline
'destination' => Pdf::DEST_BROWSER,
// your html content input
'content' => $content,
As you can see in this portion of code ..the model is obtained before all and then with this $model is defined a renderPartial with the proper view ..
for passing the $id you action should be
public function actionInvoicesPrint($id)
and for this you URL call should be
Url::to(['/your-controller/Invoices-print' , 'id' => $your_id]);
Complete Working Solution
public function actionInvoicesPrint($id)
{
$model = $this->findModel($id);
$searchModel = new InvoicesSearch();
$dataProvider = $searchModel->search(Yii::$app->request->queryParams);
$data = Invoices::findOne($id);
$content = $this->renderPartial('view', ['model' => $model,'dataProvider' => $dataProvider,'searchModel' => $searchModel,'data'=> $data]);
$pdf = new Pdf([
// set to use core fonts only
'mode' => Pdf::MODE_BLANK,
// A4 paper format
'format' => Pdf::FORMAT_A4,
// portrait orientation
'orientation' => Pdf::ORIENT_PORTRAIT,
// stream to browser inline
'destination' => Pdf::DEST_BROWSER,
// your html content input
'content' => $content,
]);
return $pdf->render();
}
IN view to trigger controller actionInvoicesPrint()
<?php
echo Html::a('<i class="fa glyphicon glyphicon-hand-up"></i> Privacy Statement', ['/invoices/invoices-print', 'id' => $model->id], [
'class'=>'btn btn-danger',
'target'=>'_blank',
'data-toggle'=>'tooltip',
'title'=>'Will open the generated PDF file in a new window'
]);
?>
Related
Im trying to generate a pdf file from month and day views of philipfrenzel-yii2fullcalendar with kartik-mpdf and I get this error
Invalid data received for parameter "events".
To do it, I've generated an actionIndexPdf($events) method in the controller and a index_pdf.php view file with the yii2fullcalendar widget receiving $events as parameter.
The problem is in the renderPartial of the action. It seems it has a problem with the array of events.
The code is as follows:
Controller CalendarioController.php
public function actionIndex() {
$calendario = Calendario::find()->all();
$events = [];
foreach ($calendario as $cal) {
$event = new \yii2fullcalendar\models\Event();
$event->id = $cal->id;
$event->title = $cal->pedido->cliente->nombre;
$event->id_pedido = $cal->pedido->id;
$event->sector = $cal->pedido->cliente->sector;
$event->direccion = $cal->pedido->cliente->direccion;
$event->telefono = $cal->pedido->cliente->telefono;
$event->textColor = '#302B16';
switch ($cal->pedido->estado) {
case 0:
$event->estado = 'Pendiente de entrega';
break;
case 1:
$event->estado = 'Entregado sin deuda';
break;
case 2:
$event->estado = 'Entregado con deuda';
break;
}
$event->start = $cal->pedido->fecha_solicitud;
$event->end = $cal->pedido->fecha_entrega;
$event->color = $cal->pedido->color;
$event->allDay = false;
$events[] = $event;
}
return $this->render('index', [
'events' => $events
]);
}
public function actionIndexPdf($events) {
die(var_dump($events));
Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
$formatter = \Yii::$app->formatter;
$pdf = new Pdf([
'mode' => Pdf::MODE_CORE, // leaner size using standard fonts
'format' => Pdf::FORMAT_LETTER,
'orientation' => Pdf::ORIENT_PORTRAIT,
'destination' => Pdf::DEST_BROWSER,
//Se renderiza la vista "pdf" (que abrirĂ¡ la nueva ventana)
'content' => $this->renderPartial('index_pdf', ['events' => $events]),
'options' => [
// any mpdf options you wish to set
],
'cssFile' => '#vendor/kartik-v/yii2-mpdf/src/assets/kv-mpdf-bootstrap.min.css',
'cssInline' => 'body{
font-size:12px;
}',
]);
return $pdf->render();
}
View index_pdf.php
<?php
/* #var $this yii\web\View */
/* #var $searchModel app\models\CalendarioSearch */
/* #var $dataProvider yii\data\ActiveDataProvider */
$this->title = 'Calendario de Pedidos';
$this->params['breadcrumbs'][] = $this->title;
?>
<p>
<?= yii2fullcalendar\yii2fullcalendar::widget([
'events' => $events,
'id' => 'calendar',
'options' => [
'lang' => 'es',
],
'clientOptions' => [
'selectable' => false,
'editable' => true,
'droppable' => true,
'header' => [
'left' => 'prev,next,today',
'center' => 'title',
'right' => 'month,listDay',
],
'height' => 'auto',
'displayEventTime' => false,
],
]);
?>
</p>
button in index.php view
<p>
<?php
//Imprime el boton generar pdf
// die(var_dump($events));
echo Html::a('Generar PDF', ['index-pdf', 'events' => $events],
[
'class' => 'btn btn-success',
'target'=>'_blank',
'data-toggle'=>'tooltip',
// 'title'=>'Will open the generated PDF file in a new window'
]);
?>
</p>
You are trying to pass an array of data as a GET parameter on this line:
echo Html::a('Generar PDF', ['index-pdf', 'events' => $events],
I imagine that passing the events array is not a requirement for you, in that case, it would be much easier to have both methods generate the array.
Since you are using the same code to get the events on both methods, index and index_pdf, you could extract that code and call it in both methods to get the $events.
You could move the code out of the controller, into a helper class for example, but, for simplicity, I will just add an example using a method inside the same controller.
private function getCalendarEvents() {
$events = [];
foreach (Calendario::find()->each() as $cal) {
$event = new \yii2fullcalendar\models\Event();
$event->id = $cal->id;
$event->title = $cal->pedido->cliente->nombre;
$event->id_pedido = $cal->pedido->id;
$event->sector = $cal->pedido->cliente->sector;
$event->direccion = $cal->pedido->cliente->direccion;
$event->telefono = $cal->pedido->cliente->telefono;
$event->textColor = '#302B16';
switch ($cal->pedido->estado) {
case 0:
$event->estado = 'Pendiente de entrega';
break;
case 1:
$event->estado = 'Entregado sin deuda';
break;
case 2:
$event->estado = 'Entregado con deuda';
break;
}
$event->start = $cal->pedido->fecha_solicitud;
$event->end = $cal->pedido->fecha_entrega;
$event->color = $cal->pedido->color;
$event->allDay = false;
$events[] = $event;
}
return $events;
}
Then call it on both actions
public function actionIndex() {
return $this->render('index', [
'events' => $this->getCalendarEvents()
]);
}
public function actionIndexPdf() {
$events = $this->getCalendarEvents();
Yii::$app->response->format = \yii\web\Response::FORMAT_RAW;
$formatter = \Yii::$app->formatter;
$pdf = new Pdf([
'mode' => Pdf::MODE_CORE, // leaner size using standard fonts
'format' => Pdf::FORMAT_LETTER,
'orientation' => Pdf::ORIENT_PORTRAIT,
'destination' => Pdf::DEST_BROWSER,
//Se renderiza la vista "pdf" (que abrirĂ¡ la nueva ventana)
'content' => $this->renderPartial('index_pdf', ['events' => $events]),
'options' => [
// any mpdf options you wish to set
],
'cssFile' => '#vendor/kartik-v/yii2-mpdf/src/assets/kv-mpdf-bootstrap.min.css',
'cssInline' => 'body{
font-size:12px;
}',
]);
return $pdf->render();
}
If passing the event array as a parameter is a requirement, you will probably need to serialize it to generate the link, and then deserialize it on the index_pdf action.
I am trying to implement the 2amigos SelectizeDropDownList widget in a form to add new values to a table directly within the dropdown.
I am using the model Book and the Model Author so basically want to be able to add a new author in the book form.
This is the book controller at the update function:
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['index']);
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}
This is the form:
<?=
$form->field($model, 'author_id')->widget(SelectizeDropDownList::className(), [
// calls an action that returns a JSON object with matched
// tags
'loadUrl' => ['author/list'],
'value' => $authors,
'items' => \yii\helpers\ArrayHelper::map(\common\models\author::find()->orderBy('name')->asArray()->all(), 'id', 'name'),
'options' => [
'class' => 'form-control',
'id' => 'id'
],
'clientOptions' => [
'valueField' => 'id',
'labelField' => 'name',
'searchField' => ['name'],
'autosearch' => ['on'],
'create' => true,
'maxItems' => 1,
],
])
?>
And this is the function author controller:
public function actionList($query) {
$models = Author::findAllByName($query);
$items = [];
foreach ($models as $model) {
$items[] = ['id' => $model->id, 'name' => $model->name];
}
Yii::$app->response->format = \Yii::$app->response->format = 'json';
return $items;
}
The form works fine to load, filter, search and add new items.
But it is not inserting the new typed attribute in the author table.
Do I need to add something in the book controller?
How can I check if it is a new value or a change of an existing author?
Thanks a lot
I made it work with the following code, not sure the most elegant because i am checking the if the author_id is a number or a string.
In my case the author won't be a number anyway.
public function actionUpdate($id) {
$model = $this->findModel($id);
if ($model->load(Yii::$app->request->post())) {
$x = Yii::$app->request->post('Book');
$new_author = $x['author_id'];
if (!is_numeric($new_author)) {
$author = new Author();
$author->name = $new_author;
$author->save();
$model->author_id = $author->id;
}
if ($model->save()) {
return $this->redirect(['index']);
}
} else {
return $this->render('update', [
'model' => $model,
'categories' => BookCategory::find()->active()->all(),
'publishers' => Publisher::find()->all(),
'copirights' => Copiright::find()->all(),
'authors' => Author::find()->all(),
]);
}
}
In the project that I want to develop, user can upload an Excel file (xls,xlsx) to system.
The excel sheet has headers in the first row, and value in another row. System has a default excel template that
consist the rule for headers sequence such as (Name, Age, Sex), but sometimes user use their own excel template so sometimes the header sequence become like this (Sex, Name, Age).
To handle this sequence, I've a plan to make a mapping process to handle the headers sequence before save the value to database. I wanna use dual list box.
I've 2 a table in database for this process:
Header -> has to column (header_id, header_name), all the headers from file has been save in here.
Each headers saved with their own header_id and header_name
Info -> the value from the excel file save here.
and I also has a pure (not generated by Gii) CostumizedHeaderController.php, CostumizeHeader.php, Index.php
This is code in CostumizeHeaderController:
class CostumizeHeaderController extends Controller {
//put your code here
public function actionShowHeaders() {
$model = new CostumizeHeader();
$model->loadHeaders();
$items = \backend\models\CostumizeHeader::getAllHeader();
return $this->render('index', [
'model' => $model,
'items' => $items
]);
}}
Code in model (CostumizeHeader.php)
class CostumizeHeader {
//put your code here
/**
* #var array IDs of the favorite foods
*/
public $list_headers = [];
public function rules() {
return [
[['list_headers'], 'string', 'max' => 255],
];
}
/**
* #return array customized attribute labels
*/
public function attributeLabels() {
return [
'list_headers' => 'list Costumized Header',
];
}
public function loadHeaders() {
$this->list_headers = [];
$headers = Header::find()->all();
foreach ($headers as $ff) {
$this->list_headers[] = $ff->header_id;
}
}
public static function getAllHeader() {
$headers = Header::find()->asArray()->all();
$items = ArrayHelper::map($headers, 'header_id', 'nama_header');
return $items;
}
code in index.php
<?php
$form = ActiveForm::begin([
'id' => 'favorite-form',
'enableAjaxValidation' => false,
]);
?>
<?= $form->field($model->list_headers, 'list_headers')->widget(DualListbox::className(), [
'model' => $model,
'items' => $items,
'name'=>'nama_header',
'attribute' => 'list_headers',
'options' => [
'multiple' => true,
'size' => 15,
],
'clientOptions' => [
'nonSelectedListLabel' => 'Available Header',
'selectedListLabel' => 'Final Header',
'moveOnSelect' => false,
],
])
->hint('Select the header according the sequence.');
?>
I've try to var_dump in controller and got this Array ( [1] => age [2] => sex [3] => name .
And I've been check the header table, and all the headers from excel file have been imported to database.
But I still got an error, like this Call to a member function formName() on a non-object.
I wish anybody can help me to solve this problem. Thankyou
Inside your view page I think you are using field incorretly $model->list_headers should be $model only.
your index.php must be as follows:
<?php
$form = ActiveForm::begin([
'id' => 'favorite-form',
'enableAjaxValidation' => false,
]);
?>
<?= $form->field($model, 'list_headers')->widget(DualListbox::className(), [
'model' => $model,
'items' => $items,
'name'=>'nama_header',
'attribute' => 'list_headers',
'options' => [
'multiple' => true,
'size' => 15,
],
'clientOptions' => [
'nonSelectedListLabel' => 'Available Header',
'selectedListLabel' => 'Final Header',
'moveOnSelect' => false,
],
])
->hint('Select the header according the sequence.');
?>
Hi i have problem with pagination in linkerPage.
My problem https://gyazo.com/cc9b04c3114d6cfd09ef376b5d4374ac
I use https://github.com/kartik-v/yii2-tabs-x
when i want using pagination I gets raw html, how on the screen.
My console browser shows error
"Resource interpreted as Document but transferred with MIME type application/json:" {my url}
My controller
public function actionTestTabs()
{
Yii::$app->response->format = Response::FORMAT_JSON;
$MovieData = seanse::find()->innerJoinWith(['idMovie', 'idRoom']
)->where(['active' => 'active'])
->groupBy('name');
$date = seanse::find()->innerJoinWith(['idMovie', 'idRoom']
)->where(['active' => 'active'])
->orderBy('name')->all();
$dataProvider = new ActiveDataProvider([
'query' => $MovieData,
'pagination' => [
'totalCount' => 1,
'pageSize' => 1,
],
]);
return $this->renderPartial('test', [
'MovieData' => $MovieData,
'dataProvider' => $dataProvider,
'date' => $date,
]);
}
My view
foreach ($month as $item) {
$items[] = [
'label' => $item,
'linkOptions' => ['data-url' => Url::to(['repertuar/test-tabs'])],
];
}
echo TabsX::widget([
'align' => TabsX::ALIGN_CENTER,
'items' => $items,
]);
what is wrong ?
Whats the problem? You've setted "json" response header in line:
Yii::$app->response->format = Response::FORMAT_JSON;
Just remove this line from code or comment it.
I have followed different implementation of file/image upload in Yii 2. One of which is from Kartik's widgets, which is in here: http://demos.krajee.com/widget-details/fileinput
In my view, _form.php:
<div class="col-sm-8">
<?php
// A block file picker button with custom icon and label
echo FileInput::widget([
'model' => $model,
'attribute' => 'image',
'options' => ['multiple' => true],
'pluginOptions' => [
'showCaption' => false,
'showRemove' => false,
'showUpload' => false,
'browseClass' => 'btn btn-primary btn-block',
'browseIcon' => '<i class="glyphicon glyphicon-camera"></i> ',
'browseLabel' => 'Upload Receipt'
],
'options' => ['accept' => 'image/*']
]);
?>
</div>
I only showed you a part of my view. That image upload block is accompanied with other fields like Customer Name, Date From and To, Product Name, etc and a Submit button.
I also have models and controllers generated already.
Part of my controller is this:
public function actionCreate()
{
$model = new Invoice();
if ($model->load(Yii::$app->request->post()) && $model->save()) {
return $this->redirect(['view', 'id' => $model->inv_id]);
}
else {
return $this->render('create', [
'model' => $model,
]);
}
}
I have not added anything yet in my actionCreate because I still don't have any idea. And in Kartik's file upload demo, there are no controllers involved or shown.
How do I save the URL/path of the image I chose to upload in my database, and save that image locally?
Edit:
Regarding #arogachev's answer, here's what my afterSave looks like in my model, but still the image path is not saved in my db:
public function afterSave($insert, $changedAttributes)
{
if(isset($this->image)){
$this->image = UploadedFile::getInstance($this,'image');
if(is_object($this->image)){
$name = Yii::$app->basePath . 'C:\wamp3\www\basicaccounting\web\uploads'; //set directory path to save image
$this->image->saveAs($name.$this->inv_id."_".$this->image);
$this->image = $this->inv_id."_".$this->image; //appending id to image name
Yii::$app->db->createCommand()
->update('invoice', ['image' => $this->image], 'inv_id = "'.$this->inv_id.'"')
->execute(); //manually update image name to db
}
}
}
Use the below aftersave in your model
public function afterSave($insert, $changedAttributes)
{
if(isset($this->logo)){
$this->logo=UploadedFile::getInstance($this,'logo');
if(is_object($this->logo)){
$path=Yii::$app->basePath . '/images/'; //set directory path to save image
$this->logo->saveAs($path.$this->id."_".$this->logo); //saving img in folder
$this->logo = $this->id."_".$this->logo; //appending id to image name
\Yii::$app->db->createCommand()
->update('organization', ['logo' => $this->logo], 'id = "'.$this->id.'"')
->execute(); //manually update image name to db
}
}
}
replace the above logo with your own attribute. ie. image
Try given below -
In your Controller
if($model->image = UploadedFile::getInstance($model, 'image'))
{
if ($model->upload())
{
// file is uploaded successfully
}
}
In your Model
public function upload()
{
$path = \Yii::$app->params['basepath'];
if (!is_dir($path)) {
$image_path = BaseFileHelper::createDirectory($path,0777,true);
}
$this->image->saveAs($path . date('Y').'/'.date('m').'/'.date('d').'/'.$this->image->baseName . '.' . $this->image->extension);
$this->image = date('Y').'/'.date('m').'/'.date('d').'/'.$this->image->baseName . '.' . $this->image->extension; // Assign image path to store in Database column (image).
return true;
}
Your image will be save on server as "$path . date('Y').'/'.date('m').'/'.date('d').'/'.$this->image->baseName . '.' . $this->image->extension".
and in the database it will be save as "date('Y').'/'.date('m').'/'.date('d').'/'.$this->image->baseName . '.' . $this->image->extension".
In form
<?= $form->field($model, 'images[]')->widget(FileInput::classname(), [
'options' => ['accept' => 'image/*', 'multiple' => true],
'pluginOptions' => [
'previewFileType' => 'image',
'allowedFileExtensions' => ['jpg', 'gif', 'png', 'bmp','jpeg'],
'showUpload' => true,
'overwriteInitial' => true,
],
]);
?>
In Model
public $images;
public function rules()
{
return [
[['name', 'price'], 'required'],
[['price'], 'integer'],
[['images'],'file', 'maxFiles' => 4],
[['name'], 'string', 'max' => 100],
];
}
In Controller
public function actionCreate()
{
$model = new Product();
if ($model->load(Yii::$app->request->post())) {
$model->save();
$file = UploadedFile::getInstances($model, 'images');
foreach ($file as $file) {
$path =Yii::getAlias('#frontend').'/uploads/'.$file->name;
$file->saveAs($path);
}
return $this->redirect(['view', 'id' => $model->id]);
}
return $this->render('create', [
'model' => $model,
]);
}