Yii2 - Generate Pdf on the fly and attach to email - pdf

This is how I can generate pdf page
public function actionPdf(){
Yii::$app->response->format = 'pdf';
$this->layout = '//print';
return $this->render('myview', []);
}
And this is how I send emails
$send = Yii::$app->mailer->compose('mytemplate',[])
->setFrom(Yii::$app->params['adminEmail'])
->setTo($email)
->setSubject($subject)
->send();
How I can generate pdf as a file and attach it to my emails on the fly?

Mailer have method called attachContent(), where you can put pdf file.
PDF should be rendered with output destination set as string, and then pass it as param to attachContent().
Sample:
Yii::$app->mail->compose()
->attachContent($pathToPdfFile, [
'fileName' => 'Name of your pdf',
'contentType' => 'application/pdf'
])
// to & subject & content of message
->send();

This is how I did it
In my controller:
$mpdf=new mPDF();
$mpdf->WriteHTML($this->renderPartial('pdf',['model' => $model])); //pdf is a name of view file responsible for this pdf document
$path = $mpdf->Output('', 'S');
Yii::$app->mail->compose()
->attachContent($path, ['fileName' => 'Invoice #'.$model->number.'.pdf', 'contentType' => 'application/pdf'])

This is how I sent mails in Yii2
private function sendPdfAsEmail($mpdf)
{
$mpdf->Output('filename.pdf', 'F');
$send = Yii::$app->mailer->compose()
->setFrom('admin#test.com')
->setTo('to#gmail.com')
->setSubject('Test Message')
->setTextBody('Plain text content. YII2 Application')
->setHtmlBody('<b>HTML content.</b>')
->attach(Yii::getAlias('#webroot').'/filename.pdf')
->send();
if($send) {
echo "Send";
}
}
Pass the mpdf instance to our custom function.
Use the F option in mpdf to save the output as a file.
use the attach option in Yii mailer and set the path of the saved file.

Related

Testing updating user profile data

I make http tests in my Laravel 5.7 application with profile page(which has "Profile View" page and "Profile Details" editor ), like :
$newUser->save();
$testing_user_id = $newUser->id;
$newUserGroup = new UserGroup();
$newUserGroup->group_id = USER_ACCESS_USER;
$newUserGroup->user_id = $newUser->id;
$userGroup= Group::find($newUserGroup->group_id);
$newUserSessionData = [
[
'loggedUserAccessGroups' => ['group_id' => $newUserGroup->group_id, 'group_name' => !empty($userGroup) ? $userGroup->name : ''],
'logged_user_ip' => '0',
]
];
$newUserGroup->save();
// 3. OPEN PROFILE PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('/profile/view');
// 3. OPEN PROFILE PAGE BLOCK END
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK START
$response->assertStatus(200); // to use HTTP_RESPONSE_OK
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 4. MAKING CHECKING PROFILE FOR USER CREATED AT 2) BLOCK END
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee(htmlspecialchars("Profile : " . $newUser->username, ENT_QUOTES));
// 5. OPEN PROFILE DETAILS VIEW PAGE BLOCK END
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/edit-details'); // http://local-votes.com/profile/edit-details
$response->assertStatus(HTTP_RESPONSE_OK);
$response->assertSee(htmlspecialchars("Profile : Details"));
// 6. OPEN PROFILE DETAILS EDITOR PAGE BLOCK END
// 7. MODIFY PROFILE DETAILS PAGE BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->post('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
'_token' => $csrf_token
]);
// $response->assertStatus(205); // ???
// 7. MODIFY PROFILE DETAILS PAGE BLOCK END
////////////////////////
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK START
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->get('profile/view');
$response->assertStatus(200);
$response->assertSee( htmlspecialchars('Modified : ' . $newUser->last_name) );
// 8. OPEN PROFILE DETAILS VIEW PAGE AFTER MODIFICATIONS BLOCK END
New user is added and Profile View page is opened ok, but there are problems at step // 7. MODIFY PROFILE DETAILS PAGE BLOCK START
as I see in sql trace new user is inserted but not updated.
In my control app/Http/Controllers/ProfileController.php update method is defined with validation request :
public function update_details(ProfileUserDetailsRequest $request)
{
$userProfile = Auth::user();
$requestData = $request->all();
$userProfile->first_name = $requestData['first_name'];
$userProfile->last_name = $requestData['last_name'];
$userProfile->phone = $requestData['phone'];
$userProfile->website = $requestData['website'];
$userProfile->updated_at = now();
$userProfile->save();
$this->setFlashMessage('Profile updated successfully !', 'success', 'Profile');
return Redirect::route('profile-view');
} // public function update_details(ProfileUserDetailsRequest $request)
1) Can the reason be in ProfileUserDetailsRequest and how to deal this ?
My profile details editor works ok.
My route defined as :
Route::group(array('prefix' => 'profile', 'middleware' => ['auth', 'isVerified']), function(){
Route::post('edit-details-post', array(
'as' => 'profile-edit-details-post',
'uses' => 'ProfileController#update_details'
));
At first I tried PUT, but after that I tried POST - the same without results.
2) Can you advice some proper way of User Profile details checking on // 7. MODIFY PROFILE DETAILS PAGE BLOCK START step ?
MODIFIED BLOCK # 2 :
I tried patch method, but it does not work anyway.
I have debugging method in my app/Http/Controllers/ProfileController.php
public function update_details(ProfileUserDetailsRequest $request)
{
method and when test is run I see that it is not triggered.
I use the same update_details method updating my form in brauser and it work ok(I see debugging info too).
I suppose that could be csrf issue and in header of my test file I wrote:
<?php
namespace Tests\Feature;
use Tests\TestCase;
use DB;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Foundation\Testing\WithoutMiddleware; // Prevent all middleware from being executed for this test class.
public function testProfilePage()
{
$csrf_token = csrf_token();
...
$response = $this->actingAs($newUser)
->withSession($newUserSessionData)
->patch('profile/edit-details-post', [
'first_name' => 'Modified : ' . $newUser->first_name,
'last_name' => 'Modified : ' . $newUser->last_name,
'phone' => 'Modified : ' . $newUser->phone,
'website' => 'Modified : ' . $newUser->website,
// '_token' => $csrf_token / I TRIED TO UNCOMMENT THIS LINE TOO
]);
$response->assertStatus(205); // making this check I see that code 419 was returned
Can decision be to add in file app/Http/Middleware/VerifyCsrfToken.php
class VerifyCsrfToken extends Middleware
{
/**
* The URIs that should be excluded from CSRF verification.
*
* #var array
*/
protected $except = [
// ???
];
If in command line I run tests as
vendor/bin/phpunit tests/Feature/ProfilepageTest.php
What have I to add in except?
Thanks!
Other than the PATCH instead of POST following are my recommendations to test your code.
Instead of ProfileUserDetailsRequest try to use simple Request.
Try to log $request variable in your update function and check if the _token and _method are available, method should be PATCH and the request variables are posted correctly.
Make a model of user table and try to update the user with that model using
$user = User::find(Auth::user()->id);
…
$user->save();
Sessions are initiated with a middleware, i think if you are disabling the middleware, session will not work.
If you are using an IDE like Visual Studio Code to run your code then try using a debugger like xdebug. Place a breakpoint in your update_details method and see if it is getting to save and save is executing. If it is then we know save is not updating correctly.
It looks like what you are doing is correct according to the documentation for update:
https://laravel.com/docs/5.7/eloquent#updates example from docs below:
$flight = App\Flight::find(1);
$flight->name = 'New Flight Name';
$flight->save();
Off the top of my head my only guess as to why it would fail is maybe getting the user off of the auth object causes problems. Take the id from the user in the auth object and use find() to grab the user then update its values and save and see if that works.

backdrop cms module-created blocks deltas not working

(tagging with drupal7 because i cannot create a tag for backdrop)
i have a fresh backdrop install, with a new theme duped from bartik, and a new layout duped from moscone_flipped. no code changes to those yet.
i have a module that creates 2 simple blocks, mostly just some html. i have implemented hook_block_info() and hook_block_view(). i can place blocks into regions in the layout using the admin ui. i can see each block on the front end page when i place either one of them. but not both. when i have both blocks placed in the layout, for some reason both regions display the output from the same block. and i have verified that it is always the first block defined in the array returned from hook_block_info(). i have cleared caches, checked code, etc.
has anyone seen this before?
btw, i just applied the recent security upgrade, and the behavior is the same both before and after the upgrade.
i will paste in the module code below, in case i have missed something.
thanks for any help anyone can provide.
// implements hook_block_info()
function mbr_block_info()
{
$info = array();
$info['rate-tables'] = array(
'info' => 'Rate Tables (Buttons)',
'description' => 'The displays the rate table links for the sidebar',
);
$info['mbr-footer'] = array(
'info' => 'MBR Footer',
'description' => 'Displays footer links, disclaimer, copyright',
);
return($info);
}
// implements hook_block_view()
function mbr_block_view($delta = '', $settings = array(), $contexts = array())
{
$block = array();
switch($delta)
{
case 'mbr-footer':
$subject = null;
$mbrFooter = getMBRFooterBlock();
$block = array('subject' => $subject, 'content' => $mbrFooter);
case 'rate-tables':
$subject = null;
$rateTables = getRateTablesBlock();
$block = array('subject' => $subject, 'content' => $rateTables);
}
return($block);
}

How to upload presentation file into Google Slides using PHP?

How can I upload presentation file (ppt, pptx, pdf) to Google Slides service using PHP.
I didn't find an example in these links:
https://developers.google.com/slides/quickstart/php
https://developers.google.com/api-client-library/php/support
My code:
$service = new Google_Service_Drive($client);
$fileMetadata = new Google_Service_Drive_DriveFile([
'name' => 'My Presentation',
'mimeType' => 'application/vnd.google-apps.presentation',
// 'mimeType' => 'application/vnd.google-apps.document',
]);
$file = $service->files->create($fileMetadata, [
'data' => file_get_contents(realpath(dirname(__FILE__)) . '/Modelo_Slide_Padrao.pptx'),
// 'mimeType' => 'application/vnd.ms-powerpoint', // 'application/pdf',
'uploadType' => 'multipart',
'fields' => 'id',
]);
printf("File ID: %s\n", $file->id);
Somebody help me?
Thank you.
You cannot upload a presentation file to Google Slides. What you are required to do is to import the file to Google Drive using a Google Doc Type. Take a look at the reference documentation which has an example of how to achieve this. Here are the examples of how to achieve what you need.
PPT to Google Slides Presentation:
$service = new Google_Service_Drive($client);
// Create a new file
$file = new Google_Service_Drive_DriveFile(array(
'name' => 'PPT Test Presentation',
'mimeType' => 'application/vnd.google-apps.presentation'
));
// Read power point ppt file
$ppt = file_get_contents("SamplePPT.ppt");
// Declare optional parameters
$optParams = array(
'uploadType' => 'multipart',
'data' => $ppt,
'mimeType' => 'application/vnd.ms-powerpoint'
);
// Import pptx file as a Google Slide presentation
$createdFile = $service->files->create($file, $optParams);
// Print google slides id
print "File id: " . $createdFile->id;
PPTX to Google Slides Presentation:
$service = new Google_Service_Drive($client);
// Create a new file
$file = new Google_Service_Drive_DriveFile(array(
'name' => 'PPTX Test Presentation',
'mimeType' => 'application/vnd.google-apps.presentation'
));
// Read Powerpoint pptx file
$pptx = file_get_contents("SamplePPTX.pptx");
// Declare opts params
$optParams = array(
'uploadType' => 'multipart',
'data' => $pptx,
'mimeType' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation'
);
// Import pptx file as a Google Slide presentation
$createdFile = $service->files->create($file, $optParams);
// Print google slides id
print "File id: " . $createdFile->id;
PDF to Google Document Doc: (is not possible to Google Slide Presentation)
$service = new Google_Service_Drive($client);
// Create a new file
$file = new Google_Service_Drive_DriveFile(array(
'name' => 'PDF Test Document',
'mimeType' => 'application/vnd.google-apps.document'
));
// Read pdf file
$pdf = file_get_contents("SamplePDF.pdf");
// Declare opts params
$optParams = array(
'uploadType' => 'multipart',
'data' => $pdf,
'mimeType' => 'application/pdf'
);
// Import pdf file as a Google Document File
$createdFile = $service->files->create($file, $optParams);
// Print google document id
print "File id: " . $createdFile->id;
The only thing that changes in each code snippet is the mimeType. For a reference of Mime Types you can visit here and for a reference of Google Mime Types you can visit here.

yii2 response formatter not being called

I'm trying to use robregonm pdfresponseFormatter to create a PDF, problem is, the pdf class is never called as the format reponse type.
'response' => [
'formatters' => [
'html' => [
'class' => 'yii\web\HtmlResponseFormatter',
],
'pdf' => [
'class' => 'robregonm\pdf\PdfResponseFormatter',
'mode' => '',
'format' => 'A4',
'defaultFontSize' => 0,
'defaultFont' => '',
'marginLeft' => 15,
'marginRight' => 15,
'marginTop' => 16,
'marginBottom' => 16,
'marginHeader' => 9,
'marginFooter' => 9,
]
]
],
....
$file = $this->getPdf($report);
....
private function getPdf($report){
Yii::$app->response->format = 'pdf';
Yii::$container->set(Yii::$app->response->formatters['pdf']['class']);
$this->layout = '//attachment';
return $this->render('pdf/actionplan', ['model' => $report]);
}
the $file variable has the HTML text in it from the view
You are asking the wrong question. Of course $file has HTML in it, you are returning HTML from your view.
Yii::$app->response->format = 'pdf';
works when the controller returns a response to the browser.
What you want to ask is why the controller function (I hope this is in a controller) does not return a PDF created from the HTML.
If you just want to save a PDF look how I handle this: https://github.com/Mihai-P/yii2-core/blob/master/components/Controller.php in the actionPdf function. That function returns a file that you can save on the server if you want.
Unfortunately I've not been able to get this extension to work. I did get kartik pdf to work great
I recommend using the kartik extension instead.

BOX-API upload file form

i'm trying to upload a file in BOX_API with php and Zend framework. But i'm missing somethin. It's the first time that i use an interface like this o i've read the manual. But it is confusig for me. My question are two:
-First, why do you have to pass to the post call only the name of the file and not the whole file with the right header for file upload? File upload in a form is not like passing the name of the file through a post call;
-secondly and consequently, do i have to make a form for file upload or simply a textarea where to write the name of the file to be passed to the BOX-API?
UPDATE:
This is the code of my upload form:
$form = new Zend_Form;
$form->setAction('/imball-reagens/public/upload')
->setMethod('post');
$file = new Zend_Form_Element_File('file');
$file->setLabel('Choose a file to upload:');
$file->addValidator('alnum');
$file->setRequired(true);
$form->addElement($file);
$access_token = new Zend_Form_Element_Hidden(array('name' => 'access_token', 'value' => $result->access_token));
$form->addElement($access_token);
$refresh_token = new Zend_Form_Element_Hidden(array('name' => 'refresh_token', 'value' => $result->refresh_token));
$form->addElement($refresh_token);
$form->addElement('submit', 'upload', array('label' => 'Upload File'));
echo $form;
And this s the POST cal to the box API which comes after the form:
$access_token= $this->getRequest()->getParam('access_token');
$client = new Zend_Http_Client('https://upload.box.com/api/2.0/files/content');
$client->setMethod(Zend_Http_Client::POST);
$client->setHeaders('Authorization: Bearer '.$access_token);
$data = $_FILES["file"]["name"];
$client->setParameterPost(array(
'filename' => '#'.$data,
'parent_id' => '0'
));
$response = $client->request()->getBody();
$this->view->response= $response;
$result = json_decode($response);
The error it throws is below:
{"type":"error","status":400,"code":"invalid_request_parameters","help_url":"http:\/\/developers.box.com\/docs\/#errors","message":"Invalid input parameters in request","request_id":"172518183652dcf2a16af73"}
Tricky to debug without seeing all of the code, but in the bit you pasted it looks like you are passing $_FILES["file"]["name"] to the API - this only contains the original name of the file which was uploaded by the user - you need to pass the location to the file on the server which is sending the data to the Box API client so that it can grab it and send it to the Box server - this should be stored in $_FILES["file"]["tmp_name"].
I would recommend changing the code to this and trying again:
$access_token= $this->getRequest()->getParam('access_token');
$client = new Zend_Http_Client('https://upload.box.com/api/2.0/files/content');
$client->setMethod(Zend_Http_Client::POST);
$client->setHeaders('Authorization: Bearer '.$access_token);
$data = $_FILES["file"]["tmp_name"];
$client->setParameterPost(array(
'parent_id' => '0'
));
$client->setFileUpload($data, 'filename');
$response = $client->request()->getBody();
$this->view->response= $response;
$result = json_decode($response);