Skip to content

Commit 3bb10ff

Browse files
authored
Merge pull request #4478 from oleibman/hyperlinkstyle
Hyperlink Styles
2 parents e65bc8b + 99f0e6a commit 3bb10ff

File tree

14 files changed

+211
-52
lines changed

14 files changed

+211
-52
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](https://semver.org).
3434
- Print Area and Row Break. [Issue #1275](https://github.com/PHPOffice/PhpSpreadsheet/issues/1275) [PR #4450](https://github.com/PHPOffice/PhpSpreadsheet/pull/4450)
3535
- Copy Styles after insertNewColumnBefore. [Issue #1425](https://github.com/PHPOffice/PhpSpreadsheet/issues/1425) [PR #4468](https://github.com/PHPOffice/PhpSpreadsheet/pull/4468)
3636
- Xls Writer Treat Hyperlink Starting with # as Internal. [Issue #56](https://github.com/PHPOffice/PhpSpreadsheet/issues/56) [PR #4453](https://github.com/PHPOffice/PhpSpreadsheet/pull/4453)
37+
- Hyperlink Styles. [Issue #1632](https://github.com/PHPOffice/PhpSpreadsheet/issues/1632) [PR #4478](https://github.com/PHPOffice/PhpSpreadsheet/pull/4478)
3738
- ODS Handling of Ceiling and Floor. [Issue #477](https://github.com/PHPOffice/PhpSpreadsheet/issues/407) [PR #4466](https://github.com/PHPOffice/PhpSpreadsheet/pull/4466)
3839
- Xlsx Reader Do Not Process Printer Settings for Dataonly. [Issue #4477](https://github.com/PHPOffice/PhpSpreadsheet/issues/4477) [PR #4480](https://github.com/PHPOffice/PhpSpreadsheet/pull/4480)
3940

docs/topics/recipes.md

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ finding a specific document in a file repository or a document
2020
management system. For example Microsoft Sharepoint uses document
2121
metadata to search for a specific document in its document lists.
2222

23-
<details>
23+
<details markdown>
2424
<summary>Click here for details of Spreadsheet Document Properties</summary>
2525

2626
These are accessed in MS Excel from the "Info" option on the "File" menu:
@@ -67,7 +67,7 @@ $spreadsheet->getProperties()
6767

6868
You can choose which properties to set or ignore.
6969

70-
<details>
70+
<details markdown>
7171
<summary>Click here for details of Property Getters/Setters</summary>
7272

7373
PhpSpreadsheet provides specific getters/setters for a number of pre-defined properties.
@@ -90,7 +90,7 @@ PhpSpreadsheet provides specific getters/setters for a number of pre-defined pro
9090
9191
</details>
9292

93-
<details>
93+
<details markdown>
9494
<summary>Click here for details of Custom Properties</summary>
9595

9696
Additionally, PhpSpreadsheet supports the creation and reading of custom properties for those file formats that accept custom properties.
@@ -143,7 +143,7 @@ $spreadsheet->getProperties()
143143

144144
A Spreadsheet consists of (very rarely) none, one or more Worksheets. If you have 1 or more Worksheets, then one (and only one) of those Worksheets can be "Active" (viewed or updated) at a time, but there will always be an "Active" Worksheet (unless you explicitly delete all of the Worksheets in the Spreadsheet).
145145

146-
<details>
146+
<details markdown>
147147
<summary>Click here for details about Worksheets</summary>
148148

149149
When you create a new Spreadsheet in MS Excel, it creates the Spreadsheet with a single Worksheet ("Sheet1")
@@ -278,7 +278,7 @@ define your own values as long as they are a valid MS Excel format.
278278
PhpSpreadsheet also provides a number of Wizards to help you create
279279
Date, Time and DateTime format masks.
280280

281-
<details>
281+
<details markdown>
282282
<summary>Click here for an example of the Date/Time Wizards</summary>
283283

284284
```php
@@ -631,17 +631,35 @@ $spreadsheet->getActiveSheet()->getCell('A1')
631631
You can make a cell a clickable URL by setting its hyperlink property:
632632

633633
```php
634-
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.phpexcel.net');
635-
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setUrl('https://www.example.com');
634+
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.example.com');
635+
$spreadsheet->getActiveSheet()->getCell('E26')
636+
->getHyperlink()
637+
->setUrl('https://www.example.com');
636638
```
637639

638640
If you want to make a hyperlink to another worksheet/cell, use the
639641
following code:
640642

641643
```php
642-
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.phpexcel.net');
643-
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setUrl("sheet://'Sheetname'!A1");
644+
$spreadsheet->getActiveSheet()
645+
->setCellValue('E27', 'go to another sheet');
646+
$spreadsheet->getActiveSheet()->getCell('E27')
647+
->getHyperlink()
648+
->setUrl("sheet://'Sheetname'!A1");
649+
```
650+
651+
Excel automatically supplies a special style when a hyperlink is
652+
entered into a cell. PhpSpreadsheet cannot do so. However,
653+
starting with release 4.3,
654+
you can mimic Excel's behavior with:
655+
```php
656+
$spreadsheet->getActiveSheet()
657+
->getStyle('E26')
658+
->getFont()
659+
->setHyperlinkTheme();
644660
```
661+
This will set underline (all formats) and text color (always
662+
for Xlsx, and usually for other formats).
645663

646664
## Setting Printer Options for Excel files
647665

@@ -824,7 +842,9 @@ $drawing = new \PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooterDrawing();
824842
$drawing->setName('PhpSpreadsheet logo');
825843
$drawing->setPath('./images/PhpSpreadsheet_logo.png');
826844
$drawing->setHeight(36);
827-
$spreadsheet->getActiveSheet()->getHeaderFooter()->addImage($drawing, \PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooter::IMAGE_HEADER_LEFT);
845+
$spreadsheet->getActiveSheet()
846+
->getHeaderFooter()
847+
->addImage($drawing, \PhpOffice\PhpSpreadsheet\Worksheet\HeaderFooter::IMAGE_HEADER_LEFT);
828848
```
829849

830850
### Setting printing breaks on a row or column
@@ -2018,7 +2038,11 @@ $richText->createText('This invoice is ');
20182038
$payable = $richText->createTextRun('payable within thirty days after the end of the month');
20192039
$payable->getFont()->setBold(true);
20202040
$payable->getFont()->setItalic(true);
2021-
$payable->getFont()->setColor( new \PhpOffice\PhpSpreadsheet\Style\Color( \PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKGREEN ) );
2041+
$payable->getFont()->setColor(
2042+
new \PhpOffice\PhpSpreadsheet\Style\Color(
2043+
\PhpOffice\PhpSpreadsheet\Style\Color::COLOR_DARKGREEN
2044+
)
2045+
);
20222046
$richText->createText(', unless specified otherwise on the invoice.');
20232047
$spreadsheet->getActiveSheet()->getCell('A18')->setValue($richText);
20242048
```

mkdocs.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,5 @@ extra_css:
77
- extra/extra.css
88
extra_javascript:
99
- extra/extrajs.js
10+
markdown_extensions:
11+
- md_in_html

samples/Basic/02_Types.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,9 +142,11 @@
142142
->getHyperlink()
143143
->setUrl('https://github.com/PHPOffice/PhpSpreadsheet')
144144
->setTooltip('Navigate to PhpSpreadsheet website');
145+
$spreadsheet->getActiveSheet()->getStyle('C17')->getFont()->setHyperlinkTheme();
145146

146147
$spreadsheet->getActiveSheet()
147148
->setCellValue('C18', '=HYPERLINK("mailto:abc@def.com","abc@def.com")');
149+
$spreadsheet->getActiveSheet()->getStyle('C18')->getFont()->setHyperlinkTheme();
148150

149151
$spreadsheet->getActiveSheet()
150152
->setCellValue('A20', 'String')

samples/templates/sampleSpreadsheet.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,18 @@
248248

249249
// Add a hyperlink to the sheet
250250
$helper->log('Add a hyperlink to an external website');
251-
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.phpexcel.net');
251+
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.example.com');
252252
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setUrl('https://www.example.com');
253253
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setTooltip('Navigate to website');
254254
$spreadsheet->getActiveSheet()->getStyle('E26')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
255+
$spreadsheet->getActiveSheet()->getStyle('E26')->getFont()->setHyperlinkTheme();
255256

256257
$helper->log('Add a hyperlink to another cell on a different worksheet within the workbook');
257258
$spreadsheet->getActiveSheet()->setCellValue('E27', 'Terms and conditions');
258259
$spreadsheet->getActiveSheet()->getCell('E27')->getHyperlink()->setUrl("sheet://'Terms and conditions'!A1");
259260
$spreadsheet->getActiveSheet()->getCell('E27')->getHyperlink()->setTooltip('Review terms and conditions');
260261
$spreadsheet->getActiveSheet()->getStyle('E27')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
262+
$spreadsheet->getActiveSheet()->getStyle('E27')->getFont()->setHyperlinkTheme();
261263

262264
// Add a drawing to the worksheet
263265
$helper->log('Add a drawing to the worksheet');

samples/templates/sampleSpreadsheet2.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,16 +248,18 @@
248248

249249
// Add a hyperlink to the sheet
250250
$helper->log('Add a hyperlink to an external website');
251-
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.phpexcel.net');
251+
$spreadsheet->getActiveSheet()->setCellValue('E26', 'www.example.com');
252252
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setUrl('https://www.example.com');
253253
$spreadsheet->getActiveSheet()->getCell('E26')->getHyperlink()->setTooltip('Navigate to website');
254254
$spreadsheet->getActiveSheet()->getStyle('E26')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
255+
$spreadsheet->getActiveSheet()->getStyle('E26')->getFont()->setHyperlinkTheme();
255256

256257
$helper->log('Add a hyperlink to another cell on a different worksheet within the workbook');
257258
$spreadsheet->getActiveSheet()->setCellValue('E27', 'Terms and conditions');
258259
$spreadsheet->getActiveSheet()->getCell('E27')->getHyperlink()->setUrl("sheet://'Terms and conditions'!A1");
259260
$spreadsheet->getActiveSheet()->getCell('E27')->getHyperlink()->setTooltip('Review terms and conditions');
260261
$spreadsheet->getActiveSheet()->getStyle('E27')->getAlignment()->setHorizontal(Alignment::HORIZONTAL_RIGHT);
262+
$spreadsheet->getActiveSheet()->getStyle('E27')->getFont()->setHyperlinkTheme();
261263

262264
// Add a drawing to the worksheet
263265
$helper->log('Add a drawing to the worksheet');

src/PhpSpreadsheet/Reader/Xlsx/Styles.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,14 @@ public function readFontStyle(Font $fontStyle, SimpleXMLElement $fontStyleXml):
104104
$attr = $this->getStyleAttributes($fontStyleXml->strike);
105105
$fontStyle->setStrikethrough(!isset($attr['val']) || self::boolean((string) $attr['val']));
106106
}
107-
$fontStyle->getColor()->setARGB($this->readColor($fontStyleXml->color));
107+
$fontStyle->getColor()
108+
->setARGB(
109+
$this->readColor($fontStyleXml->color)
110+
);
111+
$theme = $this->readColorTheme($fontStyleXml->color);
112+
if ($theme >= 0) {
113+
$fontStyle->getColor()->setTheme($theme);
114+
}
108115

109116
if (isset($fontStyleXml->u)) {
110117
$attr = $this->getStyleAttributes($fontStyleXml->u);
@@ -398,6 +405,17 @@ public function readProtectionHidden(Style $docStyle, SimpleXMLElement $style):
398405
}
399406
}
400407

408+
public function readColorTheme(SimpleXMLElement $color): int
409+
{
410+
$attr = $this->getStyleAttributes($color);
411+
$retVal = -1;
412+
if (isset($attr['theme']) && is_numeric((string) $attr['theme']) && !isset($attr['tint'])) {
413+
$retVal = (int) $attr['theme'];
414+
}
415+
416+
return $retVal;
417+
}
418+
401419
public function readColor(SimpleXMLElement $color, bool $background = false): string
402420
{
403421
$attr = $this->getStyleAttributes($color);

src/PhpSpreadsheet/Style/Color.php

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
namespace PhpOffice\PhpSpreadsheet\Style;
44

5+
use PhpOffice\PhpSpreadsheet\Theme;
6+
57
class Color extends Supervisor
68
{
79
const NAMED_COLORS = [
@@ -111,6 +113,8 @@ class Color extends Supervisor
111113

112114
private bool $hasChanged = false;
113115

116+
private int $theme = -1;
117+
114118
/**
115119
* Create a new Color.
116120
*
@@ -176,21 +180,28 @@ public function getStyleArray(array $array): array
176180
* $spreadsheet->getActiveSheet()->getStyle('B2')->getFont()->getColor()->applyFromArray(['rgb' => '808080']);
177181
* </code>
178182
*
179-
* @param array{rgb?: string, argb?: string} $styleArray Array containing style information
183+
* @param array{rgb?: string, argb?: string, theme?: int} $styleArray Array containing style information
180184
*
181185
* @return $this
182186
*/
183187
public function applyFromArray(array $styleArray): static
184188
{
185189
if ($this->isSupervisor) {
186-
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($this->getStyleArray($styleArray));
190+
$this->getActiveSheet()
191+
->getStyle($this->getSelectedCells())
192+
->applyFromArray(
193+
$this->getStyleArray($styleArray)
194+
);
187195
} else {
188196
if (isset($styleArray['rgb'])) {
189197
$this->setRGB($styleArray['rgb']);
190198
}
191199
if (isset($styleArray['argb'])) {
192200
$this->setARGB($styleArray['argb']);
193201
}
202+
if (isset($styleArray['theme'])) {
203+
$this->setTheme($styleArray['theme']);
204+
}
194205
}
195206

196207
return $this;
@@ -237,6 +248,7 @@ public function getARGB(): ?string
237248
public function setARGB(?string $colorValue = self::COLOR_BLACK, bool $nullStringOkay = false): static
238249
{
239250
$this->hasChanged = true;
251+
$this->setTheme(-1);
240252
if (!$nullStringOkay || $colorValue !== '') {
241253
$colorValue = $this->validateColor($colorValue);
242254
if ($colorValue === '') {
@@ -402,6 +414,7 @@ public function getHashCode(): string
402414

403415
return md5(
404416
$this->argb
417+
. (string) $this->theme
405418
. __CLASS__
406419
);
407420
}
@@ -411,6 +424,7 @@ protected function exportArray1(): array
411424
{
412425
$exportedArray = [];
413426
$this->exportArray2($exportedArray, 'argb', $this->getARGB());
427+
$this->exportArray2($exportedArray, 'theme', $this->getTheme());
414428

415429
return $exportedArray;
416430
}
@@ -423,4 +437,42 @@ public function getHasChanged(): bool
423437

424438
return $this->hasChanged;
425439
}
440+
441+
public function getTheme(): int
442+
{
443+
if ($this->isSupervisor) {
444+
return $this->getSharedComponent()->getTheme();
445+
}
446+
447+
return $this->theme;
448+
}
449+
450+
public function setTheme(int $theme): self
451+
{
452+
$this->hasChanged = true;
453+
454+
if ($this->isSupervisor) {
455+
$styleArray = $this->getStyleArray(['theme' => $theme]);
456+
$this->getActiveSheet()
457+
->getStyle($this->getSelectedCells())
458+
->applyFromArray($styleArray);
459+
} else {
460+
$this->theme = $theme;
461+
}
462+
463+
return $this;
464+
}
465+
466+
public function setHyperlinkTheme(): self
467+
{
468+
$rgb = $this->getActiveSheet()
469+
->getParent()
470+
?->getTheme()
471+
->getThemeColors();
472+
if (is_array($rgb) && array_key_exists('hlink', $rgb)) {
473+
$this->setRGB($rgb['hlink']);
474+
}
475+
476+
return $this->setTheme(Theme::HYPERLINK_THEME);
477+
}
426478
}

src/PhpSpreadsheet/Style/Font.php

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -206,7 +206,10 @@ public function applyFromArray(array $styleArray): static
206206
$this->setStrikethrough($styleArray['strikethrough']);
207207
}
208208
if (isset($styleArray['color'])) {
209-
$this->getColor()->applyFromArray($styleArray['color']);
209+
/** @var array{rgb?: string, argb?: string, theme?: int} */
210+
$temp = $styleArray['color'];
211+
$this->getColor()
212+
->applyFromArray($temp);
210213
}
211214
if (isset($styleArray['size'])) {
212215
$this->setSize($styleArray['size']);
@@ -398,9 +401,6 @@ public function getBold(): ?bool
398401
*/
399402
public function setBold(bool $bold): static
400403
{
401-
if ($bold == '') {
402-
$bold = false;
403-
}
404404
if ($this->isSupervisor) {
405405
$styleArray = $this->getStyleArray(['bold' => $bold]);
406406
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
@@ -430,9 +430,6 @@ public function getItalic(): ?bool
430430
*/
431431
public function setItalic(bool $italic): static
432432
{
433-
if ($italic == '') {
434-
$italic = false;
435-
}
436433
if ($this->isSupervisor) {
437434
$styleArray = $this->getStyleArray(['italic' => $italic]);
438435
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
@@ -669,10 +666,6 @@ public function getStrikethrough(): ?bool
669666
*/
670667
public function setStrikethrough(bool $strikethru): static
671668
{
672-
if ($strikethru == '') {
673-
$strikethru = false;
674-
}
675-
676669
if ($this->isSupervisor) {
677670
$styleArray = $this->getStyleArray(['strikethrough' => $strikethru]);
678671
$this->getActiveSheet()->getStyle($this->getSelectedCells())->applyFromArray($styleArray);
@@ -830,6 +823,14 @@ public function getCap(): ?string
830823
return $this->cap;
831824
}
832825

826+
public function setHyperlinkTheme(): self
827+
{
828+
$this->color->setHyperlinkTheme();
829+
$this->setUnderline(self::UNDERLINE_SINGLE);
830+
831+
return $this;
832+
}
833+
833834
/**
834835
* Implement PHP __clone to create a deep clone, not just a shallow copy.
835836
*/

src/PhpSpreadsheet/Theme.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ class Theme
88

99
private string $themeFontName = 'Office';
1010

11+
public const HYPERLINK_THEME = 10;
1112
public const COLOR_SCHEME_2013_PLUS_NAME = 'Office 2013+';
1213
public const COLOR_SCHEME_2013_PLUS = [
1314
'dk1' => '000000',

0 commit comments

Comments
 (0)