diff --git a/.phpcs.xml.dist b/.phpcs.xml.dist index 3eafb6ca1..ba381a28f 100644 --- a/.phpcs.xml.dist +++ b/.phpcs.xml.dist @@ -5,6 +5,7 @@ samples src tests + infra samples/Header.php */tests/Core/*/*Test\.(inc|css|js)$ diff --git a/infra/DocumentGenerator.php b/infra/DocumentGenerator.php index e2c3c86cb..5a86d1778 100644 --- a/infra/DocumentGenerator.php +++ b/infra/DocumentGenerator.php @@ -52,7 +52,7 @@ class DocumentGenerator return rtrim($result, ' '); } - private static function getPhpSpreadsheetFunctionText($functionCall): string + private static function getPhpSpreadsheetFunctionText(mixed $functionCall): string { if (is_string($functionCall)) { return $functionCall; diff --git a/infra/LocaleGenerator.php b/infra/LocaleGenerator.php index 5e570f7f0..508a6480e 100644 --- a/infra/LocaleGenerator.php +++ b/infra/LocaleGenerator.php @@ -38,32 +38,32 @@ class LocaleGenerator */ protected $translationBaseFolder; - protected $phpSpreadsheetFunctions; + protected array $phpSpreadsheetFunctions; /** * @var Spreadsheet */ protected $translationSpreadsheet; - protected $verbose; + protected bool $verbose; /** * @var Worksheet */ protected $localeTranslations; - protected $localeLanguageMap = []; + protected array $localeLanguageMap = []; - protected $errorCodeMap = []; + protected array $errorCodeMap = []; /** * @var Worksheet */ private $functionNameTranslations; - protected $functionNameLanguageMap = []; + protected array $functionNameLanguageMap = []; - protected $functionNameMap = []; + protected array $functionNameMap = []; public function __construct( string $translationBaseFolder, @@ -98,7 +98,7 @@ class LocaleGenerator } } - protected function buildConfigFileForLocale($column, $locale): void + protected function buildConfigFileForLocale(string $column, string $locale): void { $language = $this->localeTranslations->getCell($column . self::ENGLISH_LANGUAGE_NAME_ROW)->getValue(); $localeLanguage = $this->localeTranslations->getCell($column . self::LOCALE_LANGUAGE_NAME_ROW)->getValue(); @@ -124,7 +124,8 @@ class LocaleGenerator fclose($configFile); } - protected function writeConfigArgumentSeparator($configFile, $column): void + /** @param resource $configFile resource to write to */ + protected function writeConfigArgumentSeparator($configFile, string $column): void { $translationCell = $this->localeTranslations->getCell($column . self::ARGUMENT_SEPARATOR_ROW); $localeValue = $translationCell->getValue(); @@ -136,7 +137,8 @@ class LocaleGenerator } } - protected function writeConfigCurrencySymbol($configFile, $column): void + /** @param resource $configFile resource to write to */ + protected function writeConfigCurrencySymbol($configFile, string $column): void { $translationCell = $this->localeTranslations->getCell($column . self::CURRENCY_SYMBOL_ROW); $localeValue = $translationCell->getValue(); @@ -151,7 +153,7 @@ class LocaleGenerator } } - protected function buildFunctionsFileForLocale($column, $locale): void + protected function buildFunctionsFileForLocale(string $column, string $locale): void { $language = $this->functionNameTranslations->getCell($column . self::ENGLISH_LANGUAGE_NAME_ROW)->getValue(); $localeLanguage = $this->functionNameTranslations->getCell($column . self::LOCALE_LANGUAGE_NAME_ROW) @@ -176,6 +178,7 @@ class LocaleGenerator fclose($functionFile); } + /** @return resource used by other methods in this class */ protected function openConfigFile(string $locale, string $language, string $localeLanguage) { $this->log("Building locale {$locale} ($language) configuration"); @@ -185,11 +188,15 @@ class LocaleGenerator $this->log("Writing locale configuration to {$configFileName}"); $configFile = fopen($configFileName, 'wb'); + if ($configFile === false) { + throw new Exception('Unable to open $configFileName for write'); + } $this->writeFileHeader($configFile, $localeLanguage, $language, 'locale settings'); return $configFile; } + /** @return resource used by other methods in this class */ protected function openFunctionNameFile(string $locale, string $language, string $localeLanguage) { $this->log("Building locale {$locale} ($language) function names"); @@ -199,6 +206,9 @@ class LocaleGenerator $this->log("Writing local function names to {$functionFileName}"); $functionFile = fopen($functionFileName, 'wb'); + if ($functionFile === false) { + throw new Exception('Unable to open $functionFileName for write'); + } $this->writeFileHeader($functionFile, $localeLanguage, $language, 'function name translations'); return $functionFile; @@ -218,6 +228,7 @@ class LocaleGenerator return $localeFolder; } + /** @param resource $localeFile file being written to */ protected function writeFileHeader($localeFile, string $localeLanguage, string $language, string $title): void { fwrite($localeFile, str_repeat('#', 60) . self::EOL); @@ -229,6 +240,7 @@ class LocaleGenerator fwrite($localeFile, str_repeat('#', 60) . self::EOL . self::EOL); } + /** @param resource $localeFile file being written to */ protected function writeFileSectionHeader($localeFile, string $header): void { fwrite($localeFile, self::EOL . '##' . self::EOL); @@ -245,9 +257,6 @@ class LocaleGenerator protected function getTranslationSheet(string $sheetName): Worksheet { $worksheet = $this->translationSpreadsheet->setActiveSheetIndexByName($sheetName); - if ($worksheet === null) { - throw new Exception("{$sheetName} Worksheet not found"); - } return $worksheet; } diff --git a/phpstan.neon.dist b/phpstan.neon.dist index f6ce123ad..154541708 100644 --- a/phpstan.neon.dist +++ b/phpstan.neon.dist @@ -8,6 +8,8 @@ parameters: paths: - src/ - tests/ + - samples/ + - infra/ excludePaths: - src/PhpSpreadsheet/Chart/Renderer/JpGraph.php - src/PhpSpreadsheet/Chart/Renderer/JpGraphRendererBase.php @@ -21,3 +23,4 @@ parameters: ignoreErrors: # Accept a bit anything for assert methods - '~^Parameter \#2 .* of static method PHPUnit\\Framework\\Assert\:\:assert\w+\(\) expects .*, .* given\.$~' + - '~^Variable \$helper might not be defined\.$~' diff --git a/samples/Autofilter/10_Autofilter_selection_2.php b/samples/Autofilter/10_Autofilter_selection_2.php index 4d5d891cf..6b82bcdf5 100644 --- a/samples/Autofilter/10_Autofilter_selection_2.php +++ b/samples/Autofilter/10_Autofilter_selection_2.php @@ -126,7 +126,7 @@ $helper->log('Set country code filter (Column C) to "Germany"'); $autoFilter->getColumn('D') ->setFilterType(Column::AUTOFILTER_FILTERTYPE_DYNAMICFILTER) ->createRule() - ->setRule(Rule::AUTOFILTER_COLUMN_RULE_EQUAL, null, Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE) + ->setRule(Rule::AUTOFILTER_COLUMN_RULE_EQUAL, '', Rule::AUTOFILTER_RULETYPE_DYNAMIC_YEARTODATE) ->setRuleType(Rule::AUTOFILTER_RULETYPE_DYNAMICFILTER); $helper->log('Add filter on the Date (Column D) to display year to date'); diff --git a/samples/Basic/02_Types.php b/samples/Basic/02_Types.php index 4eaaa8b15..d28af579d 100644 --- a/samples/Basic/02_Types.php +++ b/samples/Basic/02_Types.php @@ -109,9 +109,9 @@ $richText = new RichText(); $richText->createText('你好 '); $payable = $richText->createTextRun('你 好 吗?'); -$payable->getFont()->setBold(true); -$payable->getFont()->setItalic(true); -$payable->getFont()->setColor(new Color(Color::COLOR_DARKGREEN)); +$payable->getFontOrThrow()->setBold(true); +$payable->getFontOrThrow()->setItalic(true); +$payable->getFontOrThrow()->setColor(new Color(Color::COLOR_DARKGREEN)); $richText->createText(', unless specified otherwise on the invoice.'); @@ -123,7 +123,7 @@ $richText2 = new RichText(); $richText2->createText("black text\n"); $red = $richText2->createTextRun('red text'); -$red->getFont()->setColor(new Color(Color::COLOR_RED)); +$red->getFontOrThrow()->setColor(new Color(Color::COLOR_RED)); $spreadsheet->getActiveSheet() ->getCell('C14') diff --git a/samples/Basic/19_Namedrange.php b/samples/Basic/19_Namedrange.php index 6170fa28e..5b1a25270 100644 --- a/samples/Basic/19_Namedrange.php +++ b/samples/Basic/19_Namedrange.php @@ -36,6 +36,9 @@ $spreadsheet->addNamedRange(new NamedRange('PersonLN', $spreadsheet->getActiveSh // Rename named ranges $helper->log('Rename named ranges'); +if ($spreadsheet->getNamedRange('PersonName') === null) { + throw new Exception('named range not found'); +} $spreadsheet->getNamedRange('PersonName')->setName('PersonFN'); // Rename worksheet diff --git a/samples/Basic/25_In_memory_image.php b/samples/Basic/25_In_memory_image.php index 1833e683a..7ba4871b3 100644 --- a/samples/Basic/25_In_memory_image.php +++ b/samples/Basic/25_In_memory_image.php @@ -27,12 +27,15 @@ $spreadsheet->getProperties()->setCreator('Maarten Balliauw') // Generate an image $helper->log('Generate an image'); -$gdImage = @imagecreatetruecolor(120, 20); +$gdImage = imagecreatetruecolor(120, 20); if (!$gdImage) { - exit('Cannot Initialize new GD image stream'); + throw new Exception('Cannot Initialize new GD image stream'); } $textColor = imagecolorallocate($gdImage, 255, 255, 255); +if ($textColor === false) { + throw new Exception('imagecolorallocate failed'); +} imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor); // Add a drawing to the worksheet diff --git a/samples/Basic/39_Dropdown.php b/samples/Basic/39_Dropdown.php index 0e8ff52b6..232ed0eda 100644 --- a/samples/Basic/39_Dropdown.php +++ b/samples/Basic/39_Dropdown.php @@ -20,7 +20,8 @@ $spreadsheet->getProperties() ->setDescription('Test document for PhpSpreadsheet, generated using PHP classes.') ->setKeywords('Office PhpSpreadsheet php') ->setCategory('Test result file'); -function transpose($value) + +function transpose(string $value): array { return [$value]; } @@ -30,12 +31,12 @@ $continentColumn = 'D'; $column = 'F'; // Set data for dropdowns -$continents = glob(__DIR__ . '/data/continents/*'); +$continents = glob(__DIR__ . '/data/continents/*') ?: []; foreach ($continents as $key => $filename) { $continent = pathinfo($filename, PATHINFO_FILENAME); $helper->log("Loading $continent"); $continent = str_replace(' ', '_', $continent); - $countries = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES); + $countries = file($filename, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) ?: []; $countryCount = count($countries); // Transpose $countries from a row to a column array diff --git a/samples/Calculations/Engineering/Convert-Online.php b/samples/Calculations/Engineering/Convert-Online.php index e20e4c79b..3d26a3f6b 100644 --- a/samples/Calculations/Engineering/Convert-Online.php +++ b/samples/Calculations/Engineering/Convert-Online.php @@ -77,6 +77,7 @@ if (isset($_POST['submit'])) { $quantity = $_POST['quantity']; $fromUnit = $_POST['fromUnit']; $toUnit = $_POST['toUnit']; + /** @var float|string */ $result = ConvertUOM::CONVERT($quantity, $fromUnit, $toUnit); echo "{$quantity} {$units[$_POST['category']][$fromUnit]} is {$result} {$units[$_POST['category']][$toUnit]}", PHP_EOL; diff --git a/samples/Chart/32_Chart_read_write.php b/samples/Chart/32_Chart_read_write.php index 42944c0cc..900c9567c 100644 --- a/samples/Chart/32_Chart_read_write.php +++ b/samples/Chart/32_Chart_read_write.php @@ -13,7 +13,7 @@ if ((isset($argc)) && ($argc > 1)) { $inputFileNames[] = __DIR__ . '/../templates/' . $argv[$i]; } } else { - $inputFileNames = glob($inputFileNames); + $inputFileNames = glob($inputFileNames) ?: []; } foreach ($inputFileNames as $inputFileName) { $inputFileNameShort = basename($inputFileName); @@ -40,7 +40,7 @@ foreach ($inputFileNames as $inputFileName) { } else { natsort($chartNames); foreach ($chartNames as $i => $chartName) { - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { @@ -48,15 +48,15 @@ foreach ($inputFileNames as $inputFileName) { } $helper->log(' ' . $chartName . ' - ' . $caption); $indentation = str_repeat(' ', strlen($chartName) + 3); - $groupCount = $chart->getPlotArea()->getPlotGroupCount(); + $groupCount = $chart->getPlotAreaOrThrow()->getPlotGroupCount(); if ($groupCount == 1) { - $chartType = $chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType(); + $chartType = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex(0)->getPlotType(); $helper->log($indentation . ' ' . $chartType); $helper->renderChart($chart, __FILE__); } else { $chartTypes = []; for ($i = 0; $i < $groupCount; ++$i) { - $chartTypes[] = $chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType(); + $chartTypes[] = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex($i)->getPlotType(); } $chartTypes = array_unique($chartTypes); if (count($chartTypes) == 1) { diff --git a/samples/Chart/32_Chart_read_write_HTML.php b/samples/Chart/32_Chart_read_write_HTML.php index 3cb377873..0dc5484ce 100644 --- a/samples/Chart/32_Chart_read_write_HTML.php +++ b/samples/Chart/32_Chart_read_write_HTML.php @@ -18,7 +18,7 @@ if ((isset($argc)) && ($argc > 1)) { $inputFileNames[] = __DIR__ . '/../templates/' . $argv[$i]; } } else { - $inputFileNames = glob($inputFileNames); + $inputFileNames = glob($inputFileNames) ?: []; } foreach ($inputFileNames as $inputFileName) { $inputFileNameShort = basename($inputFileName); @@ -46,22 +46,22 @@ foreach ($inputFileNames as $inputFileName) { } else { natsort($chartNames); foreach ($chartNames as $i => $chartName) { - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { - $caption = '"' . implode(' ', $chart->getTitle()->getCaption()) . '"'; + $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { $caption = 'Untitled'; } $helper->log(' ' . $chartName . ' - ' . $caption); $helper->log(str_repeat(' ', strlen($chartName) + 3)); - $groupCount = $chart->getPlotArea()->getPlotGroupCount(); + $groupCount = $chart->getPlotAreaOrThrow()->getPlotGroupCount(); if ($groupCount == 1) { - $chartType = $chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType(); + $chartType = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex(0)->getPlotType(); $helper->log(' ' . $chartType); } else { $chartTypes = []; for ($i = 0; $i < $groupCount; ++$i) { - $chartTypes[] = $chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType(); + $chartTypes[] = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex($i)->getPlotType(); } $chartTypes = array_unique($chartTypes); if (count($chartTypes) == 1) { diff --git a/samples/Chart/32_Chart_read_write_PDF.php b/samples/Chart/32_Chart_read_write_PDF.php index e3d702a9d..0ac41f71f 100644 --- a/samples/Chart/32_Chart_read_write_PDF.php +++ b/samples/Chart/32_Chart_read_write_PDF.php @@ -20,7 +20,7 @@ if ((isset($argc)) && ($argc > 1)) { $inputFileNames[] = __DIR__ . '/../templates/' . $argv[$i]; } } else { - $inputFileNames = glob($inputFileNames); + $inputFileNames = glob($inputFileNames) ?: []; } foreach ($inputFileNames as $inputFileName) { $inputFileNameShort = basename($inputFileName); @@ -48,22 +48,22 @@ foreach ($inputFileNames as $inputFileName) { } else { natsort($chartNames); foreach ($chartNames as $i => $chartName) { - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { - $caption = '"' . implode(' ', $chart->getTitle()->getCaption()) . '"'; + $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { $caption = 'Untitled'; } $helper->log(' ' . $chartName . ' - ' . $caption); $helper->log(str_repeat(' ', strlen($chartName) + 3)); - $groupCount = $chart->getPlotArea()->getPlotGroupCount(); + $groupCount = $chart->getPlotAreaOrThrow()->getPlotGroupCount(); if ($groupCount == 1) { - $chartType = $chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType(); + $chartType = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex(0)->getPlotType(); $helper->log(' ' . $chartType); } else { $chartTypes = []; for ($i = 0; $i < $groupCount; ++$i) { - $chartTypes[] = $chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType(); + $chartTypes[] = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex($i)->getPlotType(); } $chartTypes = array_unique($chartTypes); if (count($chartTypes) == 1) { diff --git a/samples/Chart/33_Chart_create_line_dateaxis.php b/samples/Chart/33_Chart_create_line_dateaxis.php index d7b674f6d..c177de79a 100644 --- a/samples/Chart/33_Chart_create_line_dateaxis.php +++ b/samples/Chart/33_Chart_create_line_dateaxis.php @@ -195,7 +195,7 @@ $spreadsheet->createSheet(); $chartSheet = $spreadsheet->getSheet(1); $chartSheet->setTitle('Scatter+Line Chart'); -$chartSheet = $spreadsheet->getSheetByName('Scatter+Line Chart'); +$chartSheet = $spreadsheet->getSheetByNameOrThrow('Scatter+Line Chart'); // Add the chart to the worksheet $chartSheet->addChart($chart); @@ -340,11 +340,14 @@ $spreadsheet->disconnectWorksheets(); function dateRange(int $nrows, Spreadsheet $wrkbk): array { - $dataSheet = $wrkbk->getSheetByName('Data'); + $dataSheet = $wrkbk->getSheetByNameOrThrow('Data'); // start the xaxis at the beginning of the quarter of the first date $startDateStr = $dataSheet->getCell('B2')->getValue(); // yyyy-mm-dd date string $startDate = DateTime::createFromFormat('Y-m-d', $startDateStr); // php date obj + if ($startDate === false) { + throw new Exception("invalid start date $startDateStr on spreadsheet"); + } // get date of first day of the quarter of the start date $startMonth = (int) $startDate->format('n'); // suppress leading zero @@ -357,12 +360,19 @@ function dateRange(int $nrows, Spreadsheet $wrkbk): array // end the xaxis at the end of the quarter of the last date $lastDateStr = $dataSheet->getCell([2, $nrows + 1])->getValue(); $lastDate = DateTime::createFromFormat('Y-m-d', $lastDateStr); + if ($lastDate === false) { + throw new Exception("invalid last date $lastDateStr on spreadsheet"); + } $lastMonth = (int) $lastDate->format('n'); $lastYr = (int) $lastDate->format('Y'); $qtr = intdiv($lastMonth, 3) + (($lastMonth % 3 > 0) ? 1 : 0); $qtrEndMonth = 3 + (($qtr - 1) * 3); $qtrEndMonth = sprintf('%02d', $qtrEndMonth); - $lastDOM = DateTime::createFromFormat('Y-m-d', "$lastYr-$qtrEndMonth-01")->format('t'); + $lastDOMDate = DateTime::createFromFormat('Y-m-d', "$lastYr-$qtrEndMonth-01"); + if ($lastDOMDate === false) { + throw new Exception("invalid last dom date $lastYr-$qtrEndMonth-01 on spreadsheet"); + } + $lastDOM = $lastDOMDate->format('t'); $qtrEndStr = "$lastYr-$qtrEndMonth-$lastDOM"; $ExcelQtrEndDateVal = SharedDate::convertIsoDate($qtrEndStr); diff --git a/samples/Chart/33_Chart_create_scatter5_trendlines.php b/samples/Chart/33_Chart_create_scatter5_trendlines.php index f58aadaf7..7467c8206 100644 --- a/samples/Chart/33_Chart_create_scatter5_trendlines.php +++ b/samples/Chart/33_Chart_create_scatter5_trendlines.php @@ -169,7 +169,7 @@ $spreadsheet->createSheet(); $chartSheet = $spreadsheet->getSheet(1); $chartSheet->setTitle('Scatter Chart'); -$chartSheet = $spreadsheet->getSheetByName('Scatter Chart'); +$chartSheet = $spreadsheet->getSheetByNameOrThrow('Scatter Chart'); // Add the chart to the worksheet $chartSheet->addChart($chart); diff --git a/samples/Chart/35_Chart_render.php b/samples/Chart/35_Chart_render.php index 4c403d993..57eb691ef 100644 --- a/samples/Chart/35_Chart_render.php +++ b/samples/Chart/35_Chart_render.php @@ -19,11 +19,13 @@ if ((isset($argc)) && ($argc > 1)) { $inputFileNames[] = __DIR__ . '/../templates/' . $argv[$i]; } } else { - $inputFileNames = glob($inputFileNames); + $inputFileNames = glob($inputFileNames) ?: []; } if (count($inputFileNames) === 1) { + /** @var string[] */ $unresolvedErrors = []; } else { + /** @var string[] */ $unresolvedErrors = [ // The following spreadsheet was created by 3rd party software, // and doesn't include the data that usually accompanies a chart. @@ -66,9 +68,9 @@ foreach ($inputFileNames as $inputFileName) { natsort($chartNames); foreach ($chartNames as $j => $chartName) { $i = $renderedCharts + $j; - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { - $caption = '"' . implode(' ', $chart->getTitle()->getCaption()) . '"'; + $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { $caption = 'Untitled'; } diff --git a/samples/Chart/35_Chart_render33.php b/samples/Chart/35_Chart_render33.php index 97091fcee..f9c7c11ad 100644 --- a/samples/Chart/35_Chart_render33.php +++ b/samples/Chart/35_Chart_render33.php @@ -10,7 +10,7 @@ require __DIR__ . '/../Header.php'; Settings::setChartRenderer(\PhpOffice\PhpSpreadsheet\Chart\Renderer\MtJpGraphRenderer::class); $inputFileType = 'Xlsx'; -$inputFileNames = $helper->getTemporaryFolder() . '/33_Chart_create_*.xlsx'; +$inputFileNamesString = $helper->getTemporaryFolder() . '/33_Chart_create_*.xlsx'; if ((isset($argc)) && ($argc > 1)) { $inputFileNames = []; @@ -18,11 +18,13 @@ if ((isset($argc)) && ($argc > 1)) { $inputFileNames[] = __DIR__ . '/../templates/' . $argv[$i]; } } else { - $inputFileNames = glob($inputFileNames); + $inputFileNames = glob($inputFileNamesString) ?: []; } if (count($inputFileNames) === 1) { + /** @var string[] */ $unresolvedErrors = []; } else { + /** @var string[] */ $unresolvedErrors = [ //'33_Chart_create_bar_stacked.xlsx', // fixed with mitoteam/jpgraph 10.3 ]; @@ -62,9 +64,9 @@ foreach ($inputFileNames as $inputFileName) { natsort($chartNames); foreach ($chartNames as $j => $chartName) { $i = $renderedCharts + $j; - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { - $caption = '"' . implode(' ', $chart->getTitle()->getCaption()) . '"'; + $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { $caption = 'Untitled'; } diff --git a/samples/Chart/37_Chart_dynamic_title.php b/samples/Chart/37_Chart_dynamic_title.php index b8b801faa..e0df17cd0 100644 --- a/samples/Chart/37_Chart_dynamic_title.php +++ b/samples/Chart/37_Chart_dynamic_title.php @@ -37,7 +37,7 @@ foreach ($inputFileNames as $inputFileName) { } else { natsort($chartNames); foreach ($chartNames as $i => $chartName) { - $chart = $worksheet->getChartByName($chartName); + $chart = $worksheet->getChartByNameOrThrow($chartName); if ($chart->getTitle() !== null) { $caption = '"' . $chart->getTitle()->getCaptionText($spreadsheet) . '"'; } else { @@ -45,15 +45,15 @@ foreach ($inputFileNames as $inputFileName) { } $helper->log(' ' . $chartName . ' - ' . $caption); $indentation = str_repeat(' ', strlen($chartName) + 3); - $groupCount = $chart->getPlotArea()->getPlotGroupCount(); + $groupCount = $chart->getPlotAreaOrThrow()->getPlotGroupCount(); if ($groupCount == 1) { - $chartType = $chart->getPlotArea()->getPlotGroupByIndex(0)->getPlotType(); + $chartType = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex(0)->getPlotType(); $helper->log($indentation . ' ' . $chartType); $helper->renderChart($chart, __FILE__, $spreadsheet); } else { $chartTypes = []; for ($i = 0; $i < $groupCount; ++$i) { - $chartTypes[] = $chart->getPlotArea()->getPlotGroupByIndex($i)->getPlotType(); + $chartTypes[] = $chart->getPlotAreaOrThrow()->getPlotGroupByIndex($i)->getPlotType(); } $chartTypes = array_unique($chartTypes); if (count($chartTypes) == 1) { diff --git a/samples/DefinedNames/CrossWorksheetNamedFormula.php b/samples/DefinedNames/CrossWorksheetNamedFormula.php index 5ce765162..6c2faec2b 100644 --- a/samples/DefinedNames/CrossWorksheetNamedFormula.php +++ b/samples/DefinedNames/CrossWorksheetNamedFormula.php @@ -40,7 +40,7 @@ setYearlyData($worksheet, '2020', $data2020); $worksheet = $spreadsheet->addSheet(new Worksheet($spreadsheet)); setYearlyData($worksheet, '2020', [], 'GROWTH'); -function setYearlyData(Worksheet $worksheet, string $year, $yearlyData, ?string $title = null): void +function setYearlyData(Worksheet $worksheet, string $year, array $yearlyData, ?string $title = null): void { // Set up some basic data $worksheetTitle = $title ?: $year; diff --git a/samples/DefinedNames/ScopedNamedRange.php b/samples/DefinedNames/ScopedNamedRange.php index aa71454df..88bc62777 100644 --- a/samples/DefinedNames/ScopedNamedRange.php +++ b/samples/DefinedNames/ScopedNamedRange.php @@ -60,12 +60,18 @@ $worksheet ->setCellValue("B{$row}", '=SUM(COLUMN_DATA_VALUES)') ->setCellValue("C{$row}", '=SUM(COLUMN_DATA_VALUES)'); +$range = $spreadsheet->getNamedRange('CHARGE_RATE'); +if ($range === null || $range->getWorksheet() === null) { + throw new Exception('expected named range not found'); +} +$chargeRateCellValue = $spreadsheet + ->getSheetByNameOrThrow($range->getWorksheet()->getTitle()) + ->getCell($range->getCellsInRange()[0])->getValue(); + $helper->log(sprintf( 'Worked %.2f hours at a rate of %s - Charge to the client is %.2f', $worksheet->getCell("B{$row}")->getCalculatedValue(), - $chargeRateCellValue = $spreadsheet - ->getSheetByName($spreadsheet->getNamedRange('CHARGE_RATE')->getWorksheet()->getTitle()) - ->getCell($spreadsheet->getNamedRange('CHARGE_RATE')->getCellsInRange()[0])->getValue(), + $chargeRateCellValue, $worksheet->getCell("C{$row}")->getCalculatedValue() )); diff --git a/samples/Pdf/21b_Pdf.php b/samples/Pdf/21b_Pdf.php index d7a1cb51e..38ba4d9c4 100644 --- a/samples/Pdf/21b_Pdf.php +++ b/samples/Pdf/21b_Pdf.php @@ -21,7 +21,7 @@ function replaceBody(string $html): string EOF; - return preg_replace($bodystring, $bodyrepl, $html); + return preg_replace($bodystring, $bodyrepl, $html) ?? ''; } require __DIR__ . '/../Header.php'; diff --git a/samples/Pdf/21c_Pdf.php b/samples/Pdf/21c_Pdf.php index f556dcb2f..6b6e6ab05 100644 --- a/samples/Pdf/21c_Pdf.php +++ b/samples/Pdf/21c_Pdf.php @@ -16,7 +16,7 @@ function addHeadersFootersMpdf2000(string $html): string odd-footer-name: html_myFooter2; EOF; - $html = preg_replace('/@page page0 {/', $pagerepl, $html); + $html = preg_replace('/@page page0 {/', $pagerepl, $html) ?? ''; $bodystring = '//'; $simulatedBodyStart = Mpdf::SIMULATED_BODY_START; $bodyrepl = << [ - 'R' => $fontFile, - ], - ]; + 'R' => $fontFile, + ], + ]; return new \Mpdf\Mpdf($config); } diff --git a/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php b/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php index 66efc3e0f..0a79dadd9 100644 --- a/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php +++ b/samples/Reader/08_Simple_file_reader_loading_several_named_worksheets.php @@ -4,9 +4,15 @@ use PhpOffice\PhpSpreadsheet\IOFactory; require __DIR__ . '/../Header.php'; +/** @return string[] */ +function getDesiredSheetNames(): array +{ + return ['Data Sheet #1', 'Data Sheet #3']; +} + $inputFileType = 'Xls'; $inputFileName = __DIR__ . '/sampleData/example1.xls'; -$sheetnames = ['Data Sheet #1', 'Data Sheet #3']; +$sheetnames = getDesiredSheetNames(); $helper->log('Loading file ' . pathinfo($inputFileName, PATHINFO_BASENAME) . ' using IOFactory with a defined reader type of ' . $inputFileType); $reader = IOFactory::createReader($inputFileType); diff --git a/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php b/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php index 437fe6cff..a8148f33c 100644 --- a/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php +++ b/samples/Reader/10_Simple_file_reader_using_a_configurable_read_filter.php @@ -13,13 +13,13 @@ $sheetname = 'Data Sheet #3'; class MyReadFilter implements IReadFilter { - private $startRow = 0; + private int $startRow = 0; - private $endRow = 0; + private int $endRow = 0; - private $columns = []; + private array $columns = []; - public function __construct($startRow, $endRow, $columns) + public function __construct(int $startRow, int $endRow, array $columns) { $this->startRow = $startRow; $this->endRow = $endRow; diff --git a/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php b/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php index ec0113261..64c5b5665 100644 --- a/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php +++ b/samples/Reader/11_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_1).php @@ -13,17 +13,14 @@ $inputFileName = __DIR__ . '/sampleData/example2.xls'; /** Define a Read Filter class implementing IReadFilter */ class ChunkReadFilter implements IReadFilter { - private $startRow = 0; + private int $startRow = 0; - private $endRow = 0; + private int $endRow = 0; /** * We expect a list of the rows that we want to read to be passed into the constructor. - * - * @param mixed $startRow - * @param mixed $chunkSize */ - public function __construct($startRow, $chunkSize) + public function __construct(int $startRow, int $chunkSize) { $this->startRow = $startRow; $this->endRow = $startRow + $chunkSize; diff --git a/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php b/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php index e8c4a6590..5b2a4e48f 100644 --- a/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php +++ b/samples/Reader/12_Reading_a_workbook_in_chunks_using_a_configurable_read_filter_(version_2).php @@ -13,17 +13,14 @@ $inputFileName = __DIR__ . '/sampleData/example2.xls'; /** Define a Read Filter class implementing IReadFilter */ class ChunkReadFilter implements IReadFilter { - private $startRow = 0; + private int $startRow = 0; - private $endRow = 0; + private int $endRow = 0; /** * Set the list of rows that we want to read. - * - * @param mixed $startRow - * @param mixed $chunkSize */ - public function setRows($startRow, $chunkSize): void + public function setRows(int $startRow, int $chunkSize): void { $this->startRow = $startRow; $this->endRow = $startRow + $chunkSize; diff --git a/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php b/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php index 82544f60a..3d6b2cb06 100644 --- a/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php +++ b/samples/Reader/14_Reading_a_large_CSV_file_in_chunks_to_split_across_multiple_worksheets.php @@ -13,17 +13,14 @@ $inputFileName = __DIR__ . '/sampleData/example2.csv'; /** Define a Read Filter class implementing IReadFilter */ class ChunkReadFilter implements IReadFilter { - private $startRow = 0; + private int $startRow = 0; - private $endRow = 0; + private int $endRow = 0; /** * Set the list of rows that we want to read. - * - * @param mixed $startRow - * @param mixed $chunkSize */ - public function setRows($startRow, $chunkSize): void + public function setRows(int $startRow, int $chunkSize): void { $this->startRow = $startRow; $this->endRow = $startRow + $chunkSize; @@ -51,8 +48,8 @@ $chunkFilter = new ChunkReadFilter(); // Tell the Reader that we want to use the Read Filter that we've Instantiated // and that we want to store it in contiguous rows/columns -$reader->setReadFilter($chunkFilter) - ->setContiguous(true); +$reader->setReadFilter($chunkFilter); +$reader->setContiguous(true); // Instantiate a new PhpSpreadsheet object manually $spreadsheet = new Spreadsheet(); diff --git a/samples/Reader/20_Reader_worksheet_hyperlink_image.php b/samples/Reader/20_Reader_worksheet_hyperlink_image.php index 2b3f294a6..19200ee21 100644 --- a/samples/Reader/20_Reader_worksheet_hyperlink_image.php +++ b/samples/Reader/20_Reader_worksheet_hyperlink_image.php @@ -14,9 +14,12 @@ $aSheet = $spreadsheet->getActiveSheet(); $gdImage = @imagecreatetruecolor(120, 20); if ($gdImage === false) { - throw new \Exception('imagecreatetruecolor failed'); + throw new Exception('imagecreatetruecolor failed'); } $textColor = imagecolorallocate($gdImage, 255, 255, 255); +if ($textColor === false) { + throw new Exception('imagecolorallocate failed'); +} imagestring($gdImage, 1, 5, 5, 'Created with PhpSpreadsheet', $textColor); $baseUrl = 'https://phpspreadsheet.readthedocs.io'; @@ -52,7 +55,7 @@ unlink($filename); $helper->log('reloaded Spreadsheet'); foreach ($reloadedSpreadsheet->getActiveSheet()->getDrawingCollection() as $pDrawing) { - $helper->log('Read link: ' . $pDrawing->getHyperlink()->getUrl()); + $helper->log('Read link: ' . ($pDrawing->getHyperlink()?->getUrl() ?? 'none')); } $helper->log('end'); diff --git a/samples/Wizards/NumberFormat/Accounting.php b/samples/Wizards/NumberFormat/Accounting.php index c09c7ca6c..20737e502 100644 --- a/samples/Wizards/NumberFormat/Accounting.php +++ b/samples/Wizards/NumberFormat/Accounting.php @@ -83,11 +83,11 @@ $currencies = [ if (isset($_POST['submit'])) { if (!is_numeric($_POST['number'])) { $helper->log('The Sample Number Value must be numeric'); - } elseif (!is_numeric($_POST['decimals']) || str_contains($_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { + } elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { $helper->log('The Decimal Places value must be positive integer'); } else { try { - $wizard = new Wizard\Accounting($_POST['currency'], $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']); + $wizard = new Wizard\Accounting($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']); $mask = $wizard->format(); $example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask); $helper->log('
Code:
'); diff --git a/samples/Wizards/NumberFormat/Currency.php b/samples/Wizards/NumberFormat/Currency.php index 87da38360..313db3194 100644 --- a/samples/Wizards/NumberFormat/Currency.php +++ b/samples/Wizards/NumberFormat/Currency.php @@ -83,11 +83,11 @@ $currencies = [ if (isset($_POST['submit'])) { if (!is_numeric($_POST['number'])) { $helper->log('The Sample Number Value must be numeric'); - } elseif (!is_numeric($_POST['decimals']) || str_contains($_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { + } elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { $helper->log('The Decimal Places value must be positive integer'); } else { try { - $wizard = new Wizard\Currency($_POST['currency'], $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']); + $wizard = new Wizard\Currency($_POST['currency'], (int) $_POST['decimals'], isset($_POST['thousands']), (bool) $_POST['position'], (bool) $_POST['spacing']); $mask = $wizard->format(); $example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask); $helper->log('
Code:
'); diff --git a/samples/Wizards/NumberFormat/Number.php b/samples/Wizards/NumberFormat/Number.php index ab2b2b3f3..274f7904a 100644 --- a/samples/Wizards/NumberFormat/Number.php +++ b/samples/Wizards/NumberFormat/Number.php @@ -49,11 +49,11 @@ if ($helper->isCli()) { if (isset($_POST['submit'])) { if (!is_numeric($_POST['number'])) { $helper->log('The Sample Number Value must be numeric'); - } elseif (!is_numeric($_POST['decimals']) || str_contains($_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { + } elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { $helper->log('The Decimal Places value must be positive integer'); } else { try { - $wizard = new Wizard\Number($_POST['decimals'], isset($_POST['thousands'])); + $wizard = new Wizard\Number((int) $_POST['decimals'], isset($_POST['thousands'])); $mask = $wizard->format(); $example = NumberFormat::toFormattedString((float) $_POST['number'], $mask); $helper->log('
Code:
'); diff --git a/samples/Wizards/NumberFormat/Percentage.php b/samples/Wizards/NumberFormat/Percentage.php index c1838827b..71b5c6911 100644 --- a/samples/Wizards/NumberFormat/Percentage.php +++ b/samples/Wizards/NumberFormat/Percentage.php @@ -43,11 +43,11 @@ if ($helper->isCli()) { if (isset($_POST['submit'])) { if (!is_numeric($_POST['number'])) { $helper->log('The Sample Number Value must be numeric'); - } elseif (!is_numeric($_POST['decimals']) || str_contains($_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { + } elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { $helper->log('The Decimal Places value must be positive integer'); } else { try { - $wizard = new Wizard\Percentage($_POST['decimals']); + $wizard = new Wizard\Percentage((int) $_POST['decimals']); $mask = $wizard->format(); $example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask); $helper->log('
Code:
'); diff --git a/samples/Wizards/NumberFormat/Scientific.php b/samples/Wizards/NumberFormat/Scientific.php index 40d390a5e..61e635d78 100644 --- a/samples/Wizards/NumberFormat/Scientific.php +++ b/samples/Wizards/NumberFormat/Scientific.php @@ -43,11 +43,11 @@ if ($helper->isCli()) { if (isset($_POST['submit'])) { if (!is_numeric($_POST['number'])) { $helper->log('The Sample Number Value must be numeric'); - } elseif (!is_numeric($_POST['decimals']) || str_contains($_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { + } elseif (!is_numeric($_POST['decimals']) || str_contains((string) $_POST['decimals'], '.') || (int) $_POST['decimals'] < 0) { $helper->log('The Decimal Places value must be positive integer'); } else { try { - $wizard = new Wizard\Scientific($_POST['decimals']); + $wizard = new Wizard\Scientific((int) $_POST['decimals']); $mask = $wizard->format(); $example = (string) NumberFormat::toFormattedString((float) $_POST['number'], $mask); $helper->log('
Code:
'); diff --git a/samples/templates/sampleSpreadsheet.php b/samples/templates/sampleSpreadsheet.php index 92e88262d..998f21105 100644 --- a/samples/templates/sampleSpreadsheet.php +++ b/samples/templates/sampleSpreadsheet.php @@ -74,19 +74,19 @@ $helper->log('Add comments'); $spreadsheet->getActiveSheet()->getComment('E11')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun('Total amount on the current invoice, excluding VAT.'); $spreadsheet->getActiveSheet()->getComment('E12')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun('Total amount of VAT on the current invoice.'); $spreadsheet->getActiveSheet()->getComment('E13')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun('Total amount on the current invoice, including VAT.'); $spreadsheet->getActiveSheet()->getComment('E13')->setWidth('100pt'); @@ -100,9 +100,9 @@ $richText = new RichText(); $richText->createText('This invoice is '); $payable = $richText->createTextRun('payable within thirty days after the end of the month'); -$payable->getFont()->setBold(true); -$payable->getFont()->setItalic(true); -$payable->getFont()->setColor(new Color(Color::COLOR_DARKGREEN)); +$payable->getFontOrThrow()->setBold(true); +$payable->getFontOrThrow()->setItalic(true); +$payable->getFontOrThrow()->setColor(new Color(Color::COLOR_DARKGREEN)); $richText->createText(', unless specified otherwise on the invoice.'); diff --git a/samples/templates/sampleSpreadsheet2.php b/samples/templates/sampleSpreadsheet2.php index 5a7beda70..76b5e0454 100644 --- a/samples/templates/sampleSpreadsheet2.php +++ b/samples/templates/sampleSpreadsheet2.php @@ -74,19 +74,19 @@ $helper->log('Add comments'); $spreadsheet->getActiveSheet()->getComment('E11')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E11')->getText()->createTextRun('Total amount on the current invoice, excluding VAT.'); $spreadsheet->getActiveSheet()->getComment('E12')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E12')->getText()->createTextRun('Total amount of VAT on the current invoice.'); $spreadsheet->getActiveSheet()->getComment('E13')->setAuthor('PhpSpreadsheet'); $commentRichText = $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun('PhpSpreadsheet:'); -$commentRichText->getFont()->setBold(true); +$commentRichText->getFontOrThrow()->setBold(true); $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun("\r\n"); $spreadsheet->getActiveSheet()->getComment('E13')->getText()->createTextRun('Total amount on the current invoice, including VAT.'); $spreadsheet->getActiveSheet()->getComment('E13')->setWidth('100pt'); @@ -100,9 +100,9 @@ $richText = new RichText(); $richText->createText('This invoice is '); $payable = $richText->createTextRun('payable within thirty days after the end of the month'); -$payable->getFont()->setBold(true); -$payable->getFont()->setItalic(true); -$payable->getFont()->setColor(new Color(Color::COLOR_DARKGREEN)); +$payable->getFontOrThrow()->setBold(true); +$payable->getFontOrThrow()->setItalic(true); +$payable->getFontOrThrow()->setColor(new Color(Color::COLOR_DARKGREEN)); $richText->createText(', unless specified otherwise on the invoice.'); diff --git a/src/PhpSpreadsheet/Cell/DataValidation.php b/src/PhpSpreadsheet/Cell/DataValidation.php index 7f1b363c5..22b285b30 100644 --- a/src/PhpSpreadsheet/Cell/DataValidation.php +++ b/src/PhpSpreadsheet/Cell/DataValidation.php @@ -140,13 +140,13 @@ class DataValidation /** * Set Formula 1. * - * @param string $formula + * @param float|int|string $formula usually string, but can be number (test for equal) * * @return $this */ public function setFormula1($formula): static { - $this->formula1 = $formula; + $this->formula1 = (string) $formula; return $this; } @@ -164,13 +164,13 @@ class DataValidation /** * Set Formula 2. * - * @param string $formula + * @param float|int|string $formula usually string, but can be number (test for equal) * * @return $this */ public function setFormula2($formula): static { - $this->formula2 = $formula; + $this->formula2 = (string) $formula; return $this; } diff --git a/src/PhpSpreadsheet/Chart/Axis.php b/src/PhpSpreadsheet/Chart/Axis.php index 7de219184..3f9249ced 100644 --- a/src/PhpSpreadsheet/Chart/Axis.php +++ b/src/PhpSpreadsheet/Chart/Axis.php @@ -124,10 +124,10 @@ class Axis extends Properties return $this->axisType === self::AXIS_TYPE_DATE || (bool) $this->axisNumber['numeric']; } - public function setAxisOption(string $key, ?string $value): void + public function setAxisOption(string $key, null|float|int|string $value): void { if ($value !== null && $value !== '') { - $this->axisOptions[$key] = $value; + $this->axisOptions[$key] = (string) $value; } } @@ -141,11 +141,11 @@ class Axis extends Properties ?string $axisOrientation = null, ?string $majorTmt = null, ?string $minorTmt = null, - ?string $minimum = null, - ?string $maximum = null, - ?string $majorUnit = null, - ?string $minorUnit = null, - ?string $textRotation = null, + null|float|int|string $minimum = null, + null|float|int|string $maximum = null, + null|float|int|string $majorUnit = null, + null|float|int|string $minorUnit = null, + null|float|int|string $textRotation = null, ?string $hidden = null, ?string $baseTimeUnit = null, ?string $majorTimeUnit = null, diff --git a/src/PhpSpreadsheet/Chart/Chart.php b/src/PhpSpreadsheet/Chart/Chart.php index b86b19cdd..2b8de5d51 100644 --- a/src/PhpSpreadsheet/Chart/Chart.php +++ b/src/PhpSpreadsheet/Chart/Chart.php @@ -285,6 +285,16 @@ class Chart return $this->plotArea; } + public function getPlotAreaOrThrow(): PlotArea + { + $plotArea = $this->getPlotArea(); + if ($plotArea !== null) { + return $plotArea; + } + + throw new Exception('Chart has no PlotArea'); + } + /** * Set Plot Area. */ diff --git a/src/PhpSpreadsheet/Chart/DataSeries.php b/src/PhpSpreadsheet/Chart/DataSeries.php index 8bceae071..647579345 100644 --- a/src/PhpSpreadsheet/Chart/DataSeries.php +++ b/src/PhpSpreadsheet/Chart/DataSeries.php @@ -124,7 +124,7 @@ class DataSeries * @param DataSeriesValues[] $plotCategory * @param DataSeriesValues[] $plotValues * @param null|string $plotDirection - * @param bool $smoothLine + * @param null|bool $smoothLine null treated as false * @param null|string $plotStyle */ public function __construct($plotType = null, $plotGrouping = null, array $plotOrder = [], array $plotLabel = [], array $plotCategory = [], array $plotValues = [], $plotDirection = null, $smoothLine = false, $plotStyle = null) @@ -144,7 +144,7 @@ class DataSeries } $this->plotCategory = $plotCategory; - $this->smoothLine = $smoothLine; + $this->smoothLine = (bool) $smoothLine; $this->plotStyle = $plotStyle; if ($plotDirection === null) { diff --git a/src/PhpSpreadsheet/Chart/DataSeriesValues.php b/src/PhpSpreadsheet/Chart/DataSeriesValues.php index a3f5ca0cf..72bbf8103 100644 --- a/src/PhpSpreadsheet/Chart/DataSeriesValues.php +++ b/src/PhpSpreadsheet/Chart/DataSeriesValues.php @@ -98,7 +98,7 @@ class DataSeriesValues extends Properties * @param mixed $dataValues * @param null|mixed $marker * @param null|ChartColor|ChartColor[]|string|string[] $fillColor - * @param string $pointSize + * @param int|string $pointSize point size */ public function __construct($dataType = self::DATASERIES_TYPE_NUMBER, $dataSource = null, $formatCode = null, $pointCount = 0, $dataValues = [], $marker = null, $fillColor = null, $pointSize = '3') { diff --git a/src/PhpSpreadsheet/Chart/Properties.php b/src/PhpSpreadsheet/Chart/Properties.php index 849f56194..740702d12 100644 --- a/src/PhpSpreadsheet/Chart/Properties.php +++ b/src/PhpSpreadsheet/Chart/Properties.php @@ -795,9 +795,9 @@ abstract class Properties * @param string $capType * @param string $joinType * @param string $headArrowType - * @param string $headArrowSize + * @param null|int|string $headArrowSize index into ARROW_SIZES array * @param string $endArrowType - * @param string $endArrowSize + * @param null|int|string $endArrowSize index into ARROW_SIZES array * @param string $headArrowWidth * @param string $headArrowLength * @param string $endArrowWidth @@ -824,7 +824,7 @@ abstract class Properties if ($headArrowType !== '') { $this->lineStyleProperties['arrow']['head']['type'] = $headArrowType; } - if (array_key_exists($headArrowSize, self::ARROW_SIZES)) { + if (isset(self::ARROW_SIZES[$headArrowSize])) { $this->lineStyleProperties['arrow']['head']['size'] = $headArrowSize; $this->lineStyleProperties['arrow']['head']['w'] = self::ARROW_SIZES[$headArrowSize]['w']; $this->lineStyleProperties['arrow']['head']['len'] = self::ARROW_SIZES[$headArrowSize]['len']; @@ -832,7 +832,7 @@ abstract class Properties if ($endArrowType !== '') { $this->lineStyleProperties['arrow']['end']['type'] = $endArrowType; } - if (array_key_exists($endArrowSize, self::ARROW_SIZES)) { + if (isset(self::ARROW_SIZES[$endArrowSize])) { $this->lineStyleProperties['arrow']['end']['size'] = $endArrowSize; $this->lineStyleProperties['arrow']['end']['w'] = self::ARROW_SIZES[$endArrowSize]['w']; $this->lineStyleProperties['arrow']['end']['len'] = self::ARROW_SIZES[$endArrowSize]['len']; diff --git a/src/PhpSpreadsheet/RichText/Run.php b/src/PhpSpreadsheet/RichText/Run.php index c2b7156e6..05d90579e 100644 --- a/src/PhpSpreadsheet/RichText/Run.php +++ b/src/PhpSpreadsheet/RichText/Run.php @@ -2,6 +2,7 @@ namespace PhpOffice\PhpSpreadsheet\RichText; +use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; use PhpOffice\PhpSpreadsheet\Style\Font; class Run extends TextElement implements ITextElement @@ -35,6 +36,15 @@ class Run extends TextElement implements ITextElement return $this->font; } + public function getFontOrThrow(): Font + { + if ($this->font === null) { + throw new SpreadsheetException('unexpected null font'); + } + + return $this->font; + } + /** * Set font. * diff --git a/src/PhpSpreadsheet/Worksheet/Worksheet.php b/src/PhpSpreadsheet/Worksheet/Worksheet.php index 89c545852..35d3ff866 100644 --- a/src/PhpSpreadsheet/Worksheet/Worksheet.php +++ b/src/PhpSpreadsheet/Worksheet/Worksheet.php @@ -662,6 +662,16 @@ class Worksheet implements IComparable return false; } + public function getChartByNameOrThrow(string $chartName): Chart + { + $chart = $this->getChartByName($chartName); + if ($chart !== false) { + return $chart; + } + + throw new Exception("Sheet does not have a chart named $chartName."); + } + /** * Refresh column dimensions. * diff --git a/tests/PhpSpreadsheetTests/Chart/ChartsByNameTest.php b/tests/PhpSpreadsheetTests/Chart/ChartsByNameTest.php new file mode 100644 index 000000000..a3583672f --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/ChartsByNameTest.php @@ -0,0 +1,97 @@ +getActiveSheet(); + $sheet->setTitle('Only Sheet'); + $sheet->fromArray( + [ + ['Some Title'], + [], + [null, null, 'Data'], + [null, 'L1', 1.3], + [null, 'L2', 1.3], + [null, 'L3', 2.3], + [null, 'L4', 1.6], + [null, 'L5', 1.5], + [null, 'L6', 1.4], + [null, 'L7', 2.2], + [null, 'L8', 1.8], + [null, 'L9', 1.1], + [null, 'L10', 1.8], + [null, 'L11', 1.6], + [null, 'L12', 2.7], + [null, 'L13', 2.2], + [null, 'L14', 1.3], + ] + ); + + $dataSeriesLabels = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, '\'Only Sheet\'!$B$4', null, 1), // 2010 + ]; + // Set the X-Axis Labels + $xAxisTickValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_STRING, '\'Only Sheet\'!$B$4:$B$17'), + ]; + // Set the Data values for each data series we want to plot + $dataSeriesValues = [ + new DataSeriesValues(DataSeriesValues::DATASERIES_TYPE_NUMBER, '\'Only Sheet\'!$C$4:$C$17'), + ]; + + // Build the dataseries + $series = new DataSeries( + DataSeries::TYPE_BARCHART, // plotType + DataSeries::GROUPING_STANDARD, // plotGrouping + range(0, count($dataSeriesValues) - 1), // plotOrder + $dataSeriesLabels, // plotLabel + $xAxisTickValues, // plotCategory + $dataSeriesValues, // plotValues + ); + + // Set the series in the plot area + $plotArea = new PlotArea(null, [$series]); + + // Create the chart + $chart = new Chart( + name: 'namedchart1', + plotArea: $plotArea, + ); + + // Set the position where the chart should appear in the worksheet + $chart->setTopLeftPosition('G7'); + $chart->setBottomRightPosition('N21'); + // Add the chart to the worksheet + $sheet->addChart($chart); + $sheet->setSelectedCells('D1'); + self::assertSame($chart, $sheet->getChartByName('namedchart1')); + self::assertSame($chart, $sheet->getChartByNameOrThrow('namedchart1')); + self::assertFalse($sheet->getChartByName('namedchart2')); + + try { + $sheet->getChartByNameOrThrow('namedchart2'); + $exceptionRaised = false; + } catch (SpreadsheetException $e) { + self::assertSame('Sheet does not have a chart named namedchart2.', $e->getMessage()); + $exceptionRaised = true; + } + + self::assertTrue($exceptionRaised); + + $spreadsheet->disconnectWorksheets(); + } +} diff --git a/tests/PhpSpreadsheetTests/Chart/PlotAreaTest.php b/tests/PhpSpreadsheetTests/Chart/PlotAreaTest.php new file mode 100644 index 000000000..819e41cec --- /dev/null +++ b/tests/PhpSpreadsheetTests/Chart/PlotAreaTest.php @@ -0,0 +1,48 @@ +getPlotAreaOrThrow()); + } + + public function testNoPlotArea(): void + { + $chart = new Chart('chart1'); + $this->expectException(ChartException::class); + $this->expectExceptionMessage('Chart has no PlotArea'); + $chart->getPlotAreaOrThrow(); + } +} diff --git a/tests/PhpSpreadsheetTests/RichTextTest.php b/tests/PhpSpreadsheetTests/RichTextTest.php index 3ebd099c0..513dcf7a9 100644 --- a/tests/PhpSpreadsheetTests/RichTextTest.php +++ b/tests/PhpSpreadsheetTests/RichTextTest.php @@ -4,6 +4,7 @@ declare(strict_types=1); namespace PhpOffice\PhpSpreadsheetTests; +use PhpOffice\PhpSpreadsheet\Exception as SpreadsheetException; use PhpOffice\PhpSpreadsheet\RichText\RichText; use PhpOffice\PhpSpreadsheet\RichText\TextElement; use PhpOffice\PhpSpreadsheet\Spreadsheet; @@ -48,4 +49,20 @@ class RichTextTest extends TestCase self::assertSame([['ABC', '-3.5']], $sheet->toArray()); $spreadsheet->disconnectWorksheets(); } + + public function testNullFont(): void + { + $richText = new RichText(); + $textRun = $richText->createTextRun('hello'); + self::assertNotNull($textRun->getFontOrThrow()); + $textRun->setFont(null); + + try { + $textRun->getFontOrThrow(); + $foundFont = true; + } catch (SpreadsheetException $e) { + $foundFont = false; + } + self::assertFalse($foundFont, 'expected exception not received'); + } }