oont-contents/plugins/woo-order-export-lite/classes/formats/class-woe-formatter-pdf.php
2025-02-10 13:57:45 +01:00

522 lines
No EOL
20 KiB
PHP

<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
include_once 'abstract-class-woe-formatter-plain-format.php';
if ( ! class_exists( 'WOE_PDF_MC_Table' ) ) {
include_once dirname( __FILE__ ) . '/../FPDF/class-woe-pdf-mc-table.php';
}
/**
* Class WOE_Formatter_PDF
*
* Using CSV formatter as basis. Works like CSV (even creates csv file) but after finish,
* fetches data from file and paste them to PDF as table
*/
class WOE_Formatter_PDF extends WOE_Formatter_Plain_Format {
/** @var $pdf WOE_PDF_MC_Table */
protected $pdf;
private $orientation = 'P';
private $page_size = 'A4';
private $font_size = 5;
private $repeat_header = false;
protected $image_format_fields;
protected $link_format_fields;
/**
* @var WOE_Formatter_Storage
*/
public $storage;
public function __construct( $mode, $filename, $settings, $format, $labels, $field_formats, $date_format, $offset ) {
$settings['enclosure'] = '"';
$settings['linebreak'] = '\r\n';
$settings['delimiter'] = ',';
$settings['encoding'] = 'UTF-8';
$this->orientation = ! empty( $settings['orientation'] ) ? $settings['orientation'] : 'P';
$this->page_size = ! empty( $settings['page_size'] ) ? $settings['page_size'] : 'A4';
$this->font_size = ! empty( $settings['font_size'] ) ? $settings['font_size'] : 5;
$this->repeat_header = ! empty( $settings['repeat_header'] );
$this->image_format_fields = array();
if ( isset( $field_formats['order']['image'] ) ) {
$this->image_format_fields = array_merge( $this->image_format_fields, $field_formats['order']['image'] );
}
if ( isset( $field_formats['products']['image'] ) ) {
$this->image_format_fields = array_merge( $this->image_format_fields, $field_formats['products']['image'] );
}
$this->image_format_fields = apply_filters( "woe_{$format}_image_format_fields", $this->image_format_fields );
$this->link_format_fields = array();
if ( isset( $field_formats['order']['link'] ) ) {
$this->link_format_fields = array_merge( $this->link_format_fields, $field_formats['order']['link'] );
}
if ( isset( $field_formats['products']['link'] ) ) {
$this->link_format_fields = array_merge( $this->link_format_fields, $field_formats['products']['link'] );
}
if( ! empty( $settings['direction_rtl'] ) ) {
foreach( $labels as $section => $section_labels ) {
$labels[$section]->set_labels( array_reverse( $section_labels->get_labels() ) );
}
}
$this->link_format_fields = apply_filters( "woe_{$format}_link_format_fields", $this->link_format_fields );
parent::__construct( $mode, $filename, $settings, $format, $labels, $field_formats, $date_format, $offset );
if ( $this->mode != 'preview' && !$this->summary_report_products && !$this->summary_report_customers ) {
$storage_filename = str_replace( '.csv', '', $filename ) . ".storage";
$this->storage = new WOE_Formatter_Storage_Csv($storage_filename);
$this->storage->load();
}
if ($this->summary_report_products || $this->summary_report_customers) {
$summaryKey = $this->summary_report_products ? WOE_Formatter_Storage_Summary_Session::SUMMARY_PRODUCTS_KEY :
WOE_Formatter_Storage_Summary_Session::SUMMARY_CUSTOMERS_KEY;
$this->storage = new WOE_Formatter_Storage_Summary_Session($summaryKey);
$this->storage->load();
}
}
public function start( $data = '' ) {
parent::start();
if ( $this->mode == 'preview' AND $this->settings['display_column_names'] ) {
$data = $this->make_header( $data );
$data = apply_filters( "woe_{$this->format}_header_filter", $data );
$this->rows[] = $data;
}
}
public function output( $rec ) {
//$rows = parent::output( $rec ); //we can't change parent because of html
$is_summary_mode = $this->summary_report_products || $this->summary_report_customers;
//was taken from parent::output()
$rec = WOE_Formatter::output( $rec );
if ($is_summary_mode) {
$rows = array($rec);
} else {
$rows = apply_filters( 'woe_fetch_order_data', $this->maybe_multiple_fields( $rec ), $this );
}
if ( $this->mode !== 'preview' || $is_summary_mode ) {
if ( ! $this->storage->getColumns() ) {
$tmpLabels = $this->make_header( "" ); //it filters labels
$tmpRow = $this->extractRowForHeaderProcess($rows);
$tmpLabels = apply_filters( "woe_{$this->format}_header_filter", $tmpLabels );
foreach ( array_keys( $tmpRow ) as $index => $key ) {
$column = new WOE_Formatter_Storage_Column();
$column->setKey( $key );
if ( $this->field_format_is( $key, $this->image_format_fields ) ) {
$column->setMetaItem( "image", true );
}
if ( $this->field_format_is( $key, $this->link_format_fields ) ) {
$column->setMetaItem( "link", true );
}
if ( isset( $tmpLabels[ $index ] ) ) {
$column->setMetaItem( "label", $tmpLabels[ $index ] );
}
$this->storage->insertColumn( $column );
}
$this->storage->saveHeader();
}
foreach ( $rows as $row ) {
if (!$row = $this->applyOutputRowFilter($row)) {
continue;
}
$rowObj = new WOE_Formatter_Storage_Row();
$rowObj->setData($row);
$rowObj->setMetaItem("order_id", (int)WC_Order_Export_Engine::$order_id);
$this->insertRowAndSave($rowObj);
}
} else {
foreach ( $rows as $row ) {
if (!$row = $this->applyOutputRowFilter($row)) {
continue;
}
$this->rows[] = $row;
}
}
return $rows;
}
public function finish_partial() {
parent::finish_partial();
$this->storage->close();
}
public function finish() {
$settings = $this->settings['global_job_settings'];
if ( preg_match('/setup_field_/i', $settings['sort']) ) {
add_filter('woe_storage_sort_by_field', function () use ($settings) {
$settings['sort'] = str_replace("setup_field__plain", "setup_field_string_plain", $settings['sort']); //fix fields with undefined format
$field = preg_replace('/setup_field_(.+?)_/i', '', $settings['sort']);
$field = str_replace("plain_orders_", "", $field); //remove extra prefix
return [$field, $settings['sort_direction'], preg_match('/setup_field_(.+?)_/i', $settings['sort'], $matches) ? $matches[1] : 'string'];
});
}
if ( $this->mode === 'preview' ) {
if($this->summary_report_products || $this->summary_report_customers) {
$this->rows = $this->storage->processDataForPreview($this->rows);
}
$this->rows = apply_filters( "woe_{$this->format}_preview_rows", $this->rows );
if ( has_filter( 'woe_storage_sort_by_field') )
$this->sort_by_custom_field();
$image_preview_multiply = 5;
$summary_row = array();
fwrite( $this->handle, '<table>' );
if ( $this->settings['display_column_names'] && count( $this->rows ) < 2 || count( $this->rows ) < 1 ) {
$this->rows[] = array( '<td colspan=10><b>' . __( 'No results', 'woo-order-export-lite' ) . '</b></td>' );
}
foreach ( $this->rows as $row_index => $row ) {
if ( empty( $this->settings['display_column_names'] ) && $row_index === 0 ) {
continue;
}
foreach ( $row as $column => &$cell ) {
if ( $this->field_format_is( $column, $this->image_format_fields ) ) {
$html = $this->make_img_html_from_path(
$cell,
$this->settings['row_images_width'] * $image_preview_multiply,
$this->settings['row_images_height'] * $image_preview_multiply );
$cell = $html ? $html : "";
}
}
unset($cell);//required or 2nd foreach will be broken!
if ( $row_index == 0 AND ! empty( $this->settings['display_column_names'] ) ) {
fwrite( $this->handle,
'<tr style="font-weight:bold"><td>' . join( '</td><td>', $row ) . "</td><tr>\n" );
} else {
fwrite( $this->handle, '<tr><td>' . join( '</td><td>', $row ) . "</td><tr>\n" );
}
foreach ( $row as $column => &$cell ) {
foreach($this->settings['global_job_settings']['order_fields'] as $order_field) {
if ( isset($order_field['key']) && ($column === $order_field['key'] || $order_field['key'] === 'plain_orders_'. $column)) {
if (!empty ($order_field['sum'])) {
$summary_row[$column] = (isset($summary_row[$column]) ? $summary_row[$column] : 0) + apply_filters("woe_summary_row_prepare_value", floatval(str_replace(',', '.', $cell)), $cell);
} else {
$summary_row[$column] = '';
}
}
}
}
}
if (!empty( array_keys($summary_row) ) && array_filter($summary_row, function ($row) { return $row !== ''; })) {
$summary_row = WOE_Formatter::output( $summary_row );
$summary_row[array_keys($summary_row)[apply_filters("woe_summary_row_title_pos",0)]] = $this->settings['global_job_settings']['summary_row_title'];
fwrite( $this->handle,
'<tr style="font-weight:bold"><td>' . join( '</td><td>', $summary_row ) . "</td><tr>\n" );
}
fwrite( $this->handle, '</table>' );
}
parent::finish();
if ( $this->mode != 'preview' ) {
$this->storage->close(); //if it's full export, storage hasn't been closed
if ( apply_filters( 'woe_pdf_output', false, $this->settings, str_replace( '.csv', '.pdf', $this->filename ) ) ) {
return;
}
if ( has_filter( 'woe_storage_sort_by_field') ) {
if( $this->summary_report_products || $this->summary_report_customers ) {
$this->storage->sortRowsByColumn( apply_filters( 'woe_storage_sort_by_field',["plain_products_name", "asc", "string"]) );
} else {
// plain export
$this->storage->loadFull();
$this->storage->sortRowsByColumn( apply_filters( 'woe_storage_sort_by_field',["plain_products_name", "asc", "string"]) );
$this->storage->forceSave();
$this->storage->close();
}
}
$this->pdf = new WOE_PDF_MC_Table( $this->orientation, 'mm', $this->page_size );
$this->storage->initRowIterator();
$row = array();
$solid_width = array();
$imageColumns = array();
$linkColumns = array();
foreach ( $this->storage->getColumns() as $pos => $column ) {
if ( $column->getMetaItem("image") === true ) {
$solid_width[ $pos ] = $this->settings['row_images_width'];
$imageColumns[] = $column->getKey();
}
if ( $column->getMetaItem("link") === true ) {
$linkColumns[] = $column->getKey();
}
}
if ( apply_filters('woe_formatter_pdf_use_external_font', false) ) {
$this->pdf = apply_filters('woe_formatter_pdf_apply_external_font', $this->pdf);
} else {
$this->pdf->setFontPath( dirname( __FILE__ ) . '/../FPDF/font/');
$this->pdf->AddFont( 'OpenSans', "", "OpenSans-Regular.ttf" );
$this->pdf->AddFont( 'OpenSans', "B", "OpenSans-Bold.ttf" );
$this->pdf->SetFont( 'OpenSans', '', $this->font_size );
}
$this->pdf->SetFillColor( null );
$pdf_props = apply_filters( 'woe_formatter_pdf_properties', array(
'header' => array(
'title' => $this->settings['header_text'],
'style' => 'B',
'size' => $this->font_size,
'text_color' => $this->hex2RGB( $this->settings['page_header_text_color'] ),
'logo' => array(
'source' => $this->settings['logo_source_id'] ? get_attached_file( $this->settings['logo_source_id'], true ) : $this->settings['logo_source'],
'width' => $this->settings['logo_width'],
'height' => $this->settings['logo_height'],
'align' => $this->settings['logo_align'],
),
),
'table' => array(
'stretch' => ! $this->settings['fit_page_width'],
'column_width' => explode( ",", $this->settings['cols_width'] ),
'solid_width' => $solid_width,
'border_style' => 'DF',
),
'table_header' => array(
'style' => 'B',
'size' => $this->font_size,
'repeat' => $this->repeat_header,
'text_color' => $this->hex2RGB( $this->settings['table_header_text_color'] ),
'background_color' => $this->hex2RGB( $this->settings['table_header_background_color'] ),
),
'table_row' => array(
'size' => $this->font_size,
'text_color' => $this->hex2RGB( $this->settings['table_row_text_color'] ),
'background_color' => $this->hex2RGB( $this->settings['table_row_background_color'] ),
'image_height' => $this->settings['row_images_height'],
),
'footer' => array(
'title' => $this->settings['footer_text'],
'style' => 'B',
'size' => $this->font_size,
'text_color' => $this->hex2RGB( $this->settings['page_footer_text_color'] ),
'pagination' => $this->settings['pagination'],
),
), $this->settings );
$this->pdf->setProperties( $pdf_props );
$this->pdf->setHorizontalAligns( explode( ",", $this->settings['cols_align'] ) );
$this->pdf->setVerticalAlign( $this->settings['cols_vertical_align'] );
do_action("woe_pdf_started", $this->pdf, $this);
$this->pdf->AliasNbPages();
$this->pdf->AddPage();
foreach ( $this->storage->getColumns() as $column ) {
$row[] = $column->getMetaItem( "label" );
}
if(!$row) // print header even if no data
$row = $this->make_header( "" );
$row = apply_filters( 'woe_row_before_format_pdf', $row );
if ( ! empty( $this->settings['display_column_names'] ) ) {
if ($this->storage instanceof WOE_Formatter_Storage_Summary_Session) {
if ($this->storage->isSummaryProducts()) {
$row = apply_filters('woe_summary_products_headers', $row);
} elseif ($this->storage->isSummaryCustomers()) {
$row = apply_filters('woe_summary_customers_headers', $row);
}
}
$row = apply_filters( 'woe_pdf_prepare_header', $row );
if( $row ) {
$this->pdf->addTableHeader( $row );
do_action("woe_pdf_below_header", $this->pdf, $this);
}
}
$pageBreakOrderLines = wc_string_to_bool( $this->settings['row_dont_page_break_order_lines'] );
// both are only for option 'row_dont_page_break_order_lines'
$orderRows = array();
$orderId = null;
$summary_row = array();
$currentRowIndex = 0;
while ( $rowObj = $this->storage->getNextRow() ) {
$row = $rowObj->getData();
foreach ( $row as $key => &$item ) {
if ( in_array($key, $imageColumns) ) {
$source = $item;
$item = array(
'type' => 'image',
'value' => $source,
);
if ( ! empty( $this->settings['row_images_add_link'] ) ) {
$item['link'] = str_replace( wp_get_upload_dir()['basedir'], wp_get_upload_dir()['baseurl'], $source );
}
}
if ( in_array($key, $linkColumns) ) {
$source = $item;
// fetch "href" attribute from "a" tag if existing
if ( preg_match( '/<a\s+(?:[^>]*?\s+)?href=(["\'])(.*?)\1/', $source, $matches ) ) {
if ( isset( $matches[2] ) ) {
$source = html_entity_decode( $matches[2] );
}
}
$item = array(
'type' => 'link',
'link' => $source,
'label' => apply_filters("woe_pdf_link_label",$source,$key,$row),
);
}
foreach($this->settings['global_job_settings']['order_fields'] as $order_field) {
if (isset($order_field['key']) && ($key === $order_field['key'] || $order_field['key'] === 'plain_orders_'. $key)) {
if (!empty ($order_field['sum'])) {
$summary_row[$key] = (isset($summary_row[$key]) ? $summary_row[$key] : 0) + apply_filters("woe_summary_row_prepare_value", floatval(str_replace(',', '.', $item)), $item);
} else {
$summary_row[$key] = '';
}
}
}
}
$currentOrderId = $rowObj->getMetaItem( "order_id" ); // always pop! even $pageBreakOrderLines is false
$orderId = ! $orderId ? $currentOrderId : $orderId;
$row = array_values( $row ); // really important to do this
$row = apply_filters( 'woe_pdf_prepare_row', $row );
$row_style = apply_filters( "woe_pdf_before_print_row", null, $row, $this->pdf, $this );
$row_height = apply_filters( "woe_pdf_row_height", null, $row, $this->pdf, $this );
if ( $pageBreakOrderLines ) {
if ( $orderId !== $currentOrderId ) {
$rows = array_map( function ( $orderRow ) {
return $orderRow[0];
}, $orderRows );
$heights = array_map( function ( $orderRow ) {
return $orderRow[2];
}, $orderRows );
if (
$currentRowIndex !== 0
&& (
!$this->pdf->isEnoughSpace($rows, $heights)
|| apply_filters("woe_pdf_page_break_before_each_order", false, $orderId)
)
) {
$this->pdf->addPageBreak();
}
foreach ( $orderRows as $orderRow ) {
$this->pdf->addRow( $orderRow[0], null, $orderRow[2], $orderRow[1] );
}
$orderRows = array();
$orderId = $currentOrderId;
}
$orderRows[] = array( $row, $row_style, $row_height );
} else {
if ($orderId !== $currentOrderId
&& $currentRowIndex !== 0
&& apply_filters("woe_pdf_page_break_before_each_order", false, $orderId)) {
$this->pdf->addPageBreak();
$orderId = $currentOrderId;
}
$this->pdf->addRow($row, null, $row_height, $row_style);
}
$currentRowIndex++;
}
if (!empty( array_keys($summary_row) ) && array_filter($summary_row, function ($row) { return $row !== ''; })) {
$summary_row = WOE_Formatter::output( $summary_row );
$summary_row[array_keys($summary_row)[0]] = $this->settings['global_job_settings']['summary_row_title'];
$summary_row = apply_filters( 'woe_pdf_prepare_row', array_values($summary_row) );
if ( $pageBreakOrderLines ) {
$orderRows[] = array( $summary_row, $row_style, $row_height );
} else {
$this->pdf->addRow( $summary_row, null, $row_height, $row_style );
}
}
if ( count( $orderRows ) ) {
$rows = array_map( function ( $orderRow ) {
return $orderRow[0];
}, $orderRows );
$heights = array_map( function ( $orderRow ) {
return $orderRow[2];
}, $orderRows );
if ( ! $this->pdf->isEnoughSpace( $rows, $heights ) OR apply_filters("woe_pdf_page_break_before_each_order", false, $orderId) ) {
$this->pdf->addPageBreak();
}
foreach ( $orderRows as $orderRow ) {
$this->pdf->addRow( $orderRow[0], null, $orderRow[2], $orderRow[1] );
}
}
do_action("woe_pdf_finished", $this->pdf, $this);
$this->pdf->output_to_destination( 'f', $this->filename );
$this->storage->close();
$this->storage->delete();
}
}
/**
* Convert a hexa decimal color code to its RGB equivalent
*
* @param string $hexStr (hexadecimal color value)
*
* @return array|boolean Returns False if invalid hex color value
*/
private function hex2RGB( $hexStr ) {
$hexStr = preg_replace( "/[^0-9A-Fa-f]/", '', $hexStr ); // Gets a proper hex string
$rgbArray = array();
if ( strlen( $hexStr ) == 6 ) { //If a proper hex code, convert using bitwise operation. No overhead... faster
$colorVal = hexdec( $hexStr );
$rgbArray[0] = 0xFF & ( $colorVal >> 0x10 );
$rgbArray[1] = 0xFF & ( $colorVal >> 0x8 );
$rgbArray[2] = 0xFF & $colorVal;
} elseif ( strlen( $hexStr ) == 3 ) { //if shorthand notation, need some string manipulations
$rgbArray[0] = hexdec( str_repeat( substr( $hexStr, 0, 1 ), 2 ) );
$rgbArray[1] = hexdec( str_repeat( substr( $hexStr, 1, 1 ), 2 ) );
$rgbArray[2] = hexdec( str_repeat( substr( $hexStr, 2, 1 ), 2 ) );
} else {
return false; //Invalid hex color code
}
return $rgbArray; // returns the rgb string or the associative array
}
}