So I am using magento 2.4.6 and have created a PDF that customer can either download or email. The PDF is created and downlaoded successfully.
Below is my code which sends an email without PDF for now, I have tried so many different approaches but still unable to attach PDF to the email.
<?php
namespace Vendor\Module\Controller\Index;
use Magento\Framework\App\Action\Action;
use Magento\Framework\App\Action\Context;
use Magento\Framework\Controller\Result\JsonFactory;
use Magento\Quote\Api\CartRepositoryInterface;
use Vendor\Module\Block\Images;
use Zend_Pdf;
use Zend_Pdf_Page;
use Zend_Pdf_Style;
use Zend_Pdf_Color_Rgb;
use Zend_Pdf_Font;
use Zend_Pdf_Image;
use Zend\Mime\Part as MimePart;
use Zend\Mime\Mime;
use Magento\Framework\App\Response\Http\FileFactory;
use Magento\Framework\Mail\Template\TransportBuilder;
use Magento\Framework\Translate\Inline\StateInterface;
use Magento\Store\Model\StoreManagerInterface;
use Magento\Framework\UrlInterface;
class GeneratePdf extends Action
{
protected $resultJsonFactory;
protected $quoteRepository;
protected $imagesBlock;
protected $transportBuilder;
protected $inlineTranslation;
protected $storeManager;
protected $fileFactory;
protected $url;
public function __construct(
Context $context,
JsonFactory $resultJsonFactory,
CartRepositoryInterface $quoteRepository,
Images $imagesBlock,
TransportBuilder $transportBuilder,
StateInterface $inlineTranslation,
StoreManagerInterface $storeManager,
FileFactory $fileFactory,
UrlInterface $url // Add this dependency
) {
$this->resultJsonFactory = $resultJsonFactory;
$this->quoteRepository = $quoteRepository;
$this->imagesBlock = $imagesBlock;
$this->transportBuilder = $transportBuilder;
$this->inlineTranslation = $inlineTranslation;
$this->storeManager = $storeManager;
$this->fileFactory = $fileFactory;
$this->url = $url; // Assign it to the class property
parent::__construct($context);
}
public function execute()
{
$quoteId = $this->getRequest()->getParam('quote_id');
$action = $this->getRequest()->getParam('action');
try {
$quote = $this->quoteRepository->get($quoteId);
$itemsByCategory = [];
foreach ($quote->getAllItems() as $item) {
$categoryId = $item->getCategoryId();
$itemsByCategory[$categoryId][] = $item;
}
$pdf = new Zend_Pdf();
$page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
$pdf->pages[] = $page;
// Get media URL and convert to file path
$mediaUrl = $this->imagesBlock->getMediaUrl('porto_child/images/foodpass_logo.png');
$baseUrl = $this->storeManager->getStore()->getBaseUrl(\Magento\Framework\UrlInterface::URL_TYPE_MEDIA);
$mediaPath = str_replace($baseUrl, '', $mediaUrl); // Remove base URL part
$imagePath = BP . '/pub/media/' . ltrim($mediaPath, '/'); // BP is Magento base path
if (file_exists($imagePath)) {
$image = Zend_Pdf_Image::imageWithPath($imagePath);
$page->drawImage($image, 30, 770, 130, 820); // Adjust coordinates as needed
} else {
throw new \Exception("Image file not found: " . $imagePath);
}
$style = new Zend_Pdf_Style();
$style->setLineColor(new Zend_Pdf_Color_Rgb(0, 0, 0));
$font = Zend_Pdf_Font::fontWithName(Zend_Pdf_Font::FONT_HELVETICA); // Using Arial (Helvetica in Zend_Pdf)
$style->setFont($font, 16);
$page->setStyle($style);
$x = 30;
$y = 730; // Adjusted to make space for the image
foreach ($itemsByCategory as $categoryId => $items) {
$categoryName = $this->imagesBlock->getCategoryNameById($categoryId);
$page->setFont($font, 16);
$page->drawText("Store: " . $categoryName, $x, $y);
$y -= 20;
$page->setFont($font, 13);
// Draw table headers
$headers = ["Product", "Format", "Brand", "Quantity", "Price"];
$headerX = [$x, $x + 150, $x + 250, $x + 350, $x + 450];
foreach ($headers as $index => $header) {
$page->drawText($header, $headerX[$index], $y);
}
$y -= 20;
// Draw table line
$page->setLineWidth(0.5);
$page->drawLine($x, $y, $x + 500, $y);
$y -= 20;
foreach ($items as $item) {
if ($y < 50) {
$page = $pdf->newPage(Zend_Pdf_Page::SIZE_A4);
$pdf->pages[] = $page;
$page->setStyle($style);
$y = 750;
}
$itemDetail = $this->imagesBlock->getProductById($item->getProductId());
// Draw item details in table format with text wrapping
$productName = $item->getName();
$price = number_format($item->getPrice(), 2); // Format price to 2 decimal places
$quantity = $item->getQty();
$productFormatAttribute = $itemDetail->getCustomAttribute('product_format');
$productFormat = $productFormatAttribute ? $productFormatAttribute->getValue() : '';
$productBrandAttribute = $itemDetail->getCustomAttribute('product_brand');
$productBrand = $productBrandAttribute ? $productBrandAttribute->getValue() : '';
// Wrap text for product name if it's too long
$maxProductNameWidth = 150;
$wrappedProductName = $this->wrapText($productName, $page->getFont(), $page->getFontSize(), $maxProductNameWidth);
// Draw the wrapped text line by line
foreach ($wrappedProductName as $line) {
$page->drawText($line, $x, $y);
$y -= 20;
}
$page->drawText($productFormat, $x + 150, $y + 20 * count($wrappedProductName)); // Draw format at correct position
$page->drawText($productBrand, $x + 250, $y + 20 * count($wrappedProductName)); // Draw brand at correct position
$page->drawText($quantity, $x + 350, $y + 20 * count($wrappedProductName)); // Draw quantity at correct position
$page->drawText($price . '$', $x + 450, $y + 20 * count($wrappedProductName)); // Draw price at correct position
$y -= 20;
}
$y -= 20; // Extra space after each category
}
$fileName = 'quote_' . $quoteId . '.pdf';
$filePath = 'var/' . $fileName;
$directory = dirname($filePath);
if (!is_dir($directory)) {
mkdir($directory, 0777, true);
}
file_put_contents($filePath, $pdf->render());
if ($action === 'email') {
$this->sendEmail($quote, $filePath);
} else {
$this->getResponse()->setHeader('Content-type', 'application/pdf');
$this->getResponse()->setHeader('Content-Disposition', 'attachment; filename="' . $fileName . '"');
$this->getResponse()->setBody(file_get_contents($filePath));
return;
}
$result = $this->resultJsonFactory->create();
return $result->setData(['pdf_url' => $this->url->getBaseUrl() . $filePath]);
} catch (\Exception $e) {
// Log the error message
$result = $this->resultJsonFactory->create();
return $result->setData(['error' => 'Error generating PDF: ' . $e->getMessage()]);
}
}
protected function wrapText($text, $font, $fontSize, $maxWidth)
{
$wrappedLines = [];
$words = explode(' ', $text);
$line = '';
foreach ($words as $word) {
$testLine = $line ? $line . ' ' . $word : $word;
$testWidth = $this->getTextWidth($testLine, $font, $fontSize);
if ($testWidth <= $maxWidth) {
$line = $testLine;
} else {
if ($line) {
$wrappedLines[] = $line;
}
$line = $word;
}
}
if ($line) {
$wrappedLines[] = $line;
}
return $wrappedLines;
}
protected function getTextWidth($text, $font, $fontSize)
{
$drawingText = iconv('UTF-8', 'UTF-16BE//IGNORE', $text);
$characters = [];
for ($i = 0; $i < strlen($drawingText); $i++) {
$characters[] = (ord($drawingText[$i++]) << 8) | ord($drawingText[$i]);
}
$glyphs = $font->glyphNumbersForCharacters($characters);
$widths = $font->widthsForGlyphs($glyphs);
$textWidth = (array_sum($widths) / $font->getUnitsPerEm()) * $fontSize;
return $textWidth;
}
public function sendEmail($quote, $filePath)
{
$writer = new \Zend_Log_Writer_Stream(BP . '/var/log/custom.log');
$logger = new \Zend_Log();
$logger->addWriter($writer);
try {
$customerEmail = $quote->getCustomerEmail();
$this->inlineTranslation->suspend();
$sender = [
'name' => 'Emailname',
'email' => '[email protected]'
];
$transport = $this->transportBuilder
->setTemplateIdentifier('foodpass_quote_email_template')
->setTemplateOptions(
[
'area' => \Magento\Framework\App\Area::AREA_FRONTEND,
'store' => \Magento\Store\Model\Store::DEFAULT_STORE_ID,
]
)
->setTemplateVars([
'templateVar' => 'My Topic',
])
->setFrom($sender)
->addTo($customerEmail)
->getTransport();
$transport->sendMessage();
$this->inlineTranslation->resume();
} catch (\Exception $e) {
$logger->info($e->getMessage());
$this->logger->debug($e->getMessage());
}
}
}