Merged in feature/PMCORE-2095 (pull request #7475)

PMCORE-2095 - Add New Fonts for Output Documents

Approved-by: Paula Quispe <paula.quispe@processmaker.com>
Approved-by: Julio Cesar Laura Avendaño <contact@julio-laura.com>
This commit is contained in:
Julio Cesar Laura Avendaño
2020-09-16 20:39:38 +00:00
154 changed files with 1369 additions and 7 deletions

View File

@@ -2,6 +2,7 @@
namespace Tests\unit\workflow\engine\classes\model;
use Faker\Factory;
use G;
use OutputDocument;
use ProcessMaker\Model\OutputDocument as OutputDocumentModel;
@@ -14,6 +15,30 @@ use Tests\TestCase;
*/
class OutputDocumentTest extends TestCase
{
var $faker = null;
/**
* OutputDocumentTest constructor.
* @param string $name
* @param array $data
* @param string $dataName
*/
public function __construct($name = null, array $data = [], $dataName = '')
{
// Faker instance
$this->faker = Factory::create();
// Check if the constant "K_PATH_FONTS" is defined, if is not defined we need to define
if (!defined('K_PATH_FONTS')) {
// Generate a new folder name
$folderName = $this->faker->word;
// Define the path of the fonts, "K_PATH_FONTS" is a constant used by "TCPDF" library
define('K_PATH_FONTS', PATH_DATA . 'fonts' . PATH_SEP . $folderName . PATH_SEP);
}
// Parent constructor
parent::__construct($name, $data, $dataName);
}
/**
* Review the generate pdf using TCPDF
@@ -68,7 +93,216 @@ class OutputDocumentTest extends TestCase
$properties
);
$this->assertFileExists($pathOutput . $output->OUT_DOC_FILENAME . '.pdf');
// Remove the shared folder
G::rm_dir($fonts);
}
/**
* Test checkTcPdfFontsPath method
*
* @test
* @covers \OutputDocument::checkTcPdfFontsPath()
*/
public function it_should_test_check_tcpdf_fonts_path()
{
// Generate a new folder name
$folderName = $this->faker->word;
// Check if the TCPDF fonts path exists, if not exists should be created and initialized
OutputDocument::checkTcPdfFontsPath($folderName);
// Assertion
$this->assertDirectoryExists(K_PATH_FONTS);
}
/**
* Test loadTcPdfFontsList method
*
* @test
* @covers \OutputDocument::loadTcPdfFontsList()
*/
public function it_should_test_load_tcpdf_fonts_list()
{
// Get fonts
$fonts = OutputDocument::loadTcPdfFontsList();
// Assertion
$this->assertTrue(is_array($fonts));
}
/**
* Test saveTcPdfFontsList method
*
* @test
* @covers \OutputDocument::saveTcPdfFontsList()
*/
public function it_should_test_save_tcpdf_fonts_list()
{
// Get fonts stored originally
$fontsOriginal = OutputDocument::loadTcPdfFontsList();
// Set variables needed
$fontFamily = $this->faker->word;
$font = [
'fileName' => "{$fontFamily}.ttf",
'tcPdfFileName' => $fontFamily,
'familyName' => $fontFamily,
'inTinyMce' => true,
'friendlyName' => $fontFamily,
'properties' => ''
];
$fontsToSave = $fontsOriginal;
$fontsToSave[] = $font;
// Check if TCPDF fonts paths exists
if (!file_exists(K_PATH_FONTS)) {
G::mk_dir(K_PATH_FONTS);
}
// Save fonts
OutputDocument::saveTcPdfFontsList($fontsToSave);
// Get fonts
$fontsModified = OutputDocument::loadTcPdfFontsList();
// Assertion
$this->assertTrue(count($fontsModified) > count($fontsOriginal));
}
/**
* Test addTcPdfFont method
*
* @test
* @covers \OutputDocument::addTcPdfFont()
*/
public function it_should_test_add_tcpdf_font()
{
// Set variables needed
$fontFamily = $this->faker->word;
$font = [
'fileName' => "{$fontFamily}.ttf",
'tcPdfFileName' => $fontFamily,
'familyName' => $fontFamily,
'inTinyMce' => true,
'friendlyName' => $fontFamily,
'properties' => ''
];
// Check if TCPDF fonts paths exists
if (!file_exists(K_PATH_FONTS)) {
G::mk_dir(K_PATH_FONTS);
}
// Add new font
OutputDocument::addTcPdfFont($font);
// Get fonts
$fonts = OutputDocument::loadTcPdfFontsList();
// Assertion
$this->assertArrayHasKey("{$fontFamily}.ttf", $fonts);
}
/**
* Test existTcpdfFont method
*
* @test
* @covers \OutputDocument::existTcpdfFont()
*/
public function it_should_test_exist_tcpdf_font()
{
// Generate a fake family name
$fontFamily = $this->faker->word;
// Add a new font
$font = [
'fileName' => "{$fontFamily}.ttf",
'tcPdfFileName' => $fontFamily,
'familyName' => $fontFamily,
'inTinyMce' => true,
'friendlyName' => $fontFamily,
'properties' => ''
];
// Check if TCPDF fonts paths exists
if (!file_exists(K_PATH_FONTS)) {
G::mk_dir(K_PATH_FONTS);
}
// Add new font
OutputDocument::addTcPdfFont($font);
// Assertion
$this->assertTrue(OutputDocument::existTcpdfFont("{$fontFamily}.ttf"));
}
/**
* Test removeTcPdfFont method
*
* @test
* @covers \OutputDocument::removeTcPdfFont()
*/
public function it_should_test_remove_tcpdf_font()
{
// Generate a fake family name
$fontFamily = $this->faker->word;
// Add a new font
$font = [
'fileName' => "{$fontFamily}.ttf",
'tcPdfFileName' => $fontFamily,
'familyName' => $fontFamily,
'inTinyMce' => true,
'friendlyName' => $fontFamily,
'properties' => ''
];
// Check if TCPDF fonts paths exists
if (!file_exists(K_PATH_FONTS)) {
G::mk_dir(K_PATH_FONTS);
}
// Add new font
OutputDocument::addTcPdfFont($font);
// Remove font
OutputDocument::removeTcPdfFont("{$fontFamily}.ttf");
// Assertion
$this->assertFalse(OutputDocument::existTcpdfFont("{$fontFamily}.ttf"));
}
/**
* Test generateCssFile method
*
* @test
* @covers \OutputDocument::generateCssFile()
*/
public function it_should_test_generate_css_file()
{
// Set variables needed
$fontFamily = $this->faker->word;
$font = [
'fileName' => "{$fontFamily}.ttf",
'tcPdfFileName' => $fontFamily,
'familyName' => $fontFamily,
'inTinyMce' => true,
'friendlyName' => $fontFamily,
'properties' => ''
];
$fontsToSave = ["{$fontFamily}.ttf" => $font];
// Check if TCPDF fonts paths exists
if (!file_exists(K_PATH_FONTS)) {
G::mk_dir(K_PATH_FONTS);
}
// Save fonts
OutputDocument::saveTcPdfFontsList($fontsToSave);
// Re-generate CSS file
OutputDocument::generateCssFile();
// Assertion
$cssContent = file_get_contents(K_PATH_FONTS . 'fonts.css');
$this->assertTrue(strpos($cssContent, "{$fontFamily}.ttf") !== false);
}
}

View File

@@ -386,6 +386,48 @@ EOT
);
CLI::taskRun("run_artisan");
/**
* Add a font to be used in Documents generation (TinyMCE editor and/or TCPDF library)
*/
CLI::taskName('documents-add-font');
CLI::taskDescription(<<<EOT
Add a font to be used in Documents generation (TinyMCE editor and/or TCPDF library).
EOT
);
CLI::taskOpt('type', <<<EOT
Can be "TrueType" or "TrueTypeUnicode", if the option is not specified the default value is "TrueType"
EOT
,'t', 'type=');
CLI::taskOpt('tinymce', <<<EOT
Can be "true" or "false", if the option is not specified the default value is "true". If the value is "false" the optional arguments [FRIENDLYNAME] [FONTPROPERTIES] are omitted.
EOT
,'tm', 'tinymce=');
CLI::taskArg('fontFileName', false);
CLI::taskArg('friendlyName', true);
CLI::taskArg('fontProperties', true);
CLI::taskRun('documents_add_font');
/**
* List the registered fonts
*/
CLI::taskName('documents-list-registered-fonts');
CLI::taskDescription(<<<EOT
List the registered fonts.
EOT
);
CLI::taskRun('documents_list_registered_fonts');
/**
* Remove a font used in Documents generation (TinyMCE editor and/or TCPDF library)
*/
CLI::taskName('documents-remove-font');
CLI::taskDescription(<<<EOT
Remove a font used in Documents generation (TinyMCE editor and/or TCPDF library).
EOT
);
CLI::taskArg('fontFileName', false);
CLI::taskRun('documents_remove_font');
/**
* Function run_info
*
@@ -1407,3 +1449,160 @@ function run_artisan($args)
CLI::logging("> The --workspace option is undefined.\n");
}
}
/**
* Add a font to be used in Documents generation (TinyMCE editor and/or TCPDF library)
*
* @param array $args
* @param array $options
*/
function documents_add_font($args, $options)
{
try {
// Validate the main required argument
if (empty($args)) {
throw new Exception('Please send the font filename.');
}
// Load and initialize optional arguments and options
$fontFileName = $args[0];
$fontFriendlyName = $args[1] ?? '';
$fontProperties = $args[2] ?? '';
$fontType = $options['type'] ?? 'TrueType';
$inTinyMce = !empty($options['tinymce']) ? $options['tinymce'] === 'true' : true;
$name = '';
// Check fonts path
OutputDocument::checkTcPdfFontsPath();
// Check if the font file exist
if (!file_exists(PATH_DATA . 'fonts' . PATH_SEP . $fontFileName)) {
throw new Exception("Font '{$fontFileName}' not exists.");
}
// Check if the font file was already added
if (OutputDocument::existTcpdfFont($fontFileName)) {
throw new Exception("Font '{$fontFileName}' already added.");
}
// Check if the friendly font name is valid
if (preg_match('/[^0-9A-Za-z ]/', $fontFriendlyName)) {
throw new Exception('The friendly font name is using an incorrect format please use only letters, numbers and spaces.');
}
// Check if the font type is valid
if (!in_array($fontType, ['TrueType', 'TrueTypeUnicode'])) {
throw new Exception("Font type '{$fontType}' is invalid.");
}
// Convert TTF file to the format required by TCPDF library
$tcPdfFileName = TCPDF_FONTS::addTTFfont(PATH_DATA . 'fonts' . PATH_SEP . $fontFileName, $fontType);
// Check if the conversion was successful
if ($tcPdfFileName === false) {
throw new Exception("The font file '{$fontFileName}' cannot be converted.");
}
// Include font definition, in order to use the variable $name
require_once K_PATH_FONTS . $tcPdfFileName . '.php';
// Build the font family name to be used in the styles
$fontFamilyName = strtolower($name);
$fontFamilyName = str_replace('-', ' ', $fontFamilyName);
$fontFamilyName = str_replace(['bold', 'oblique', 'italic', 'regular'], '', $fontFamilyName);
$fontFamilyName = trim($fontFamilyName);
// Add new font
$font = [
'fileName' => $fontFileName,
'tcPdfFileName' => $tcPdfFileName,
'familyName' => $fontFamilyName,
'inTinyMce' => $inTinyMce,
'friendlyName' => !empty($fontFriendlyName) ? $fontFriendlyName : $fontFamilyName,
'properties' => $fontProperties
];
OutputDocument::addTcPdfFont($font);
// Print finalization message
CLI::logging("Font '{$fontFileName}' added successfully." . PHP_EOL . PHP_EOL);
} catch (Exception $e) {
// Display the error message
CLI::logging($e->getMessage() . PHP_EOL . PHP_EOL);
}
}
/**
* List the registered fonts
*/
function documents_list_registered_fonts()
{
// Check fonts path
OutputDocument::checkTcPdfFontsPath();
// Get registered fonts
$fonts = OutputDocument::loadTcPdfFontsList();
// Display information
CLI::logging(PHP_EOL);
if (!empty($fonts)) {
foreach ($fonts as $fileName => $font) {
$inTinyMce = $font['inTinyMce'] ? 'Yes' : 'No';
CLI::logging("TTF Filename: {$fileName}" . PHP_EOL);
CLI::logging("TCPDF Filename: {$font['tcPdfFileName']}" . PHP_EOL);
CLI::logging("Display in TinyMCE: {$inTinyMce}" . PHP_EOL . PHP_EOL . PHP_EOL);
}
} else {
CLI::logging('It has not been added fonts yet.' . PHP_EOL . PHP_EOL);
}
}
/**
* Remove a font used in Documents generation (TinyMCE editor and/or TCPDF library)
*
* @param array $args
*/
function documents_remove_font($args)
{
try {
// Validate the main required argument
if (empty($args)) {
throw new Exception('Please send the font filename.');
}
// Load arguments
$fontFileName = $args[0];
// Check fonts path
OutputDocument::checkTcPdfFontsPath();
// Check if the font file exist
if (!file_exists(PATH_DATA . 'fonts' . PATH_SEP . $fontFileName)) {
throw new Exception("Font '{$fontFileName}' not exists.");
}
// Check if the font file was registered
if (!OutputDocument::existTcpdfFont($fontFileName)) {
throw new Exception("Font '{$fontFileName}' was not registered.");
}
// Get registered font
$font = OutputDocument::loadTcPdfFontsList()[$fontFileName];
// Remove TCPDF font files
$extensions = ['ctg.z', 'php', 'z'];
foreach ($extensions as $extension) {
if (file_exists(PATH_DATA . 'fonts' . PATH_SEP . 'tcpdf' . PATH_SEP . $font['tcPdfFileName'] . '.' . $extension)) {
unlink(PATH_DATA . 'fonts' . PATH_SEP . 'tcpdf' . PATH_SEP . $font['tcPdfFileName'] . '.' . $extension);
}
}
// Remove font
OutputDocument::removeTcPdfFont($fontFileName);
// Print finalization message
CLI::logging("Font '{$fontFileName}' removed successfully." . PHP_EOL . PHP_EOL);
} catch (Exception $e) {
// Display the error message
CLI::logging($e->getMessage() . PHP_EOL . PHP_EOL);
}
}

View File

@@ -1,5 +1,6 @@
<?php
use Illuminate\Filesystem\Filesystem;
use ProcessMaker\Core\System;
class OutputDocument extends BaseOutputDocument
@@ -796,6 +797,9 @@ class OutputDocument extends BaseOutputDocument
*/
public function generateTcpdf($outDocUid, $fields, $path, $filename, $content, $landscape = false, $properties = [])
{
// Check and prepare the fonts path used by TCPDF library
self::checkTcPdfFontsPath();
// Including the basic configuration for the TCPDF library
require_once PATH_TRUNK . "vendor" . PATH_SEP . "tecnickcom" . PATH_SEP . "tcpdf" . PATH_SEP . "config" . PATH_SEP . "tcpdf_config.php";
@@ -924,13 +928,30 @@ class OutputDocument extends BaseOutputDocument
// Enable the font sub-setting option
$pdf->setFontSubsetting(true);
// Set unicode font if is required, we need to detect if is chinese, japanese, thai, etc.
// Set default unicode font if is required, we need to detect if is chinese, japanese, thai, etc.
if (preg_match('/[\x{30FF}\x{3040}-\x{309F}\x{4E00}-\x{9FFF}\x{0E00}-\x{0E7F}]/u', $content, $matches)) {
// The additional fonts should be in "shared/fonts" folder
$fileArialUniTTF = PATH_DATA . "fonts" . PATH_SEP . "arialuni.ttf";
$fileArialUniTTF = PATH_DATA . 'fonts' . PATH_SEP . 'arialuni.ttf';
if (file_exists($fileArialUniTTF)) {
$font = TCPDF_FONTS::addTTFfont($fileArialUniTTF, 'TrueTypeUnicode');
$pdf->SetFont($font);
// Convert TTF file to the format required by TCPDF library
$tcPdfFileName = TCPDF_FONTS::addTTFfont($fileArialUniTTF, 'TrueTypeUnicode');
// Set the default unicode font for the document
$pdf->SetFont($tcPdfFileName);
// Register the font file if is not present in the JSON file
if (!self::existTcpdfFont('arialuni.ttf')) {
// Add font "arialuni.ttf"
$font = [
'fileName' => 'arialuni.ttf',
'tcPdfFileName' => $tcPdfFileName,
'familyName' => $tcPdfFileName,
'inTinyMce' => true,
'friendlyName' => $tcPdfFileName,
'properties' => ''
];
self::addTcPdfFont($font);
}
}
}
@@ -1200,4 +1221,145 @@ class OutputDocument extends BaseOutputDocument
throw ($oError);
}
}
/**
* Check and prepare the fonts path used by TCPDF library
*
* @param string $folderName
*/
public static function checkTcPdfFontsPath($folderName = 'tcpdf')
{
if (!defined('K_PATH_FONTS')) {
// Define the path of the fonts, "K_PATH_FONTS" is a constant used by "TCPDF" library
define('K_PATH_FONTS', PATH_DATA . 'fonts' . PATH_SEP . $folderName . PATH_SEP);
}
// Check if already exists the path, if not exist we need to prepare the same
if (!file_exists(K_PATH_FONTS)) {
// Instance Filesystem class
$filesystem = new Filesystem();
// Create the missing folder(s)
$filesystem->makeDirectory(K_PATH_FONTS, 0755, true, true);
// Copy files related to the fonts from vendors
$filesystem->copyDirectory(PATH_TRUNK . 'vendor' . PATH_SEP . 'tecnickcom' . PATH_SEP . 'tcpdf' . PATH_SEP . 'fonts' . PATH_SEP, K_PATH_FONTS);
// Copy files related to the fonts from core
$filesystem->copyDirectory(PATH_CORE . 'content' . PATH_SEP . 'tcPdfFonts' . PATH_SEP, K_PATH_FONTS);
}
}
/**
* Load the custom fonts list
*
* @return array
*/
public static function loadTcPdfFontsList()
{
// Initialize variables
$jsonFilePath = K_PATH_FONTS . 'fonts.json';
// Load the custom fonts list
if (file_exists($jsonFilePath)) {
$fonts = json_decode(file_get_contents($jsonFilePath), true);
} else {
$fonts = [];
}
return $fonts;
}
/**
* Save the custom fonts list
*
* @param $fonts
*/
public static function saveTcPdfFontsList($fonts)
{
// Initialize variables
$jsonFilePath = K_PATH_FONTS . 'fonts.json';
// Save the JSON file
file_put_contents($jsonFilePath, json_encode($fonts));
}
/**
* Check if a font file name exist in the fonts list
*
* @param string $fontFileName
* @return bool
*/
public static function existTcpdfFont($fontFileName)
{
// Load the custom fonts list
$fonts = self::loadTcPdfFontsList();
// Exist?
return isset($fonts[$fontFileName]);
}
/**
* Add a custom font to be used by TCPDF library
*
* @param array $font
*/
public static function addTcPdfFont($font)
{
// Load the custom fonts list
$fonts = self::loadTcPdfFontsList();
// Add the font
$fonts[$font['fileName']] = $font;
// Save the fonts list
self::saveTcPdfFontsList($fonts);
// Re-generate CSS file
self::generateCssFile();
}
/**
* Remove a custom font used in TCPDF library
*
* @param string $fileName
*/
public static function removeTcPdfFont($fileName)
{
// Load the custom fonts list
$fonts = self::loadTcPdfFontsList();
// Add the font
unset($fonts[$fileName]);
// Save the fonts list
self::saveTcPdfFontsList($fonts);
// Re-generate CSS file
self::generateCssFile();
}
/**
* Generate CSS with the fonts definition to be used by TinyMCE editor
*/
public static function generateCssFile()
{
// Initialize variables
$template = "@font-face {font-family: @familyName;src: url('/fonts/font.php?file=@fileName') format('truetype');@properties}\n";
$css = '';
// Load the custom fonts list
$fonts = self::loadTcPdfFontsList();
// Build the CSS content
foreach ($fonts as $font) {
if ($font['inTinyMce']) {
$css .= str_replace(['@familyName', '@fileName', '@properties'],
[$font['familyName'], $font['fileName'], $font['properties']], $template);
}
}
// Save the CSS file
file_put_contents(K_PATH_FONTS . 'fonts.css', $css);
}
}

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

Binary file not shown.

File diff suppressed because one or more lines are too long

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More