Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
E
Export to Excel
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Container Registry
Model registry
Operate
Environments
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
Community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
Extensions
Export to Excel
Commits
03e931b9
Commit
03e931b9
authored
6 years ago
by
bgm
Committed by
Aegir user
6 years ago
Browse files
Options
Downloads
Patches
Plain Diff
Report export: set column widths, wrap text, changes to file name, file metadata.
parent
416f1c9f
No related branches found
Branches containing commit
No related tags found
Tags containing commit
No related merge requests found
Changes
1
Hide whitespace changes
Inline
Side-by-side
Showing
1 changed file
CRM/CiviExportExcel/Utils/Report.php
+201
-10
201 additions, 10 deletions
CRM/CiviExportExcel/Utils/Report.php
with
201 additions
and
10 deletions
CRM/CiviExportExcel/Utils/Report.php
+
201
−
10
View file @
03e931b9
<?php
use
CRM_Civiexportexcel_ExtensionUtil
as
E
;
use
PhpOffice\PhpSpreadsheet\Spreadsheet
;
use
PhpOffice\PhpSpreadsheet\Writer\Xlsx
;
use
PhpOffice\PhpSpreadsheet\Worksheet\Worksheet
;
use
PhpOffice\PhpSpreadsheet\Worksheet\Row
;
use
PhpOffice\PhpSpreadsheet\Cell\Cell
;
use
PhpOffice\PhpSpreadsheet\Cell\Coordinate
;
/**
* @package civiexportexcel
* @copyright Mathieu Lutfy (c) 2014-2015
*/
class
CRM_CiviExportExcel_Utils_Report
extends
CRM_Core_Page
{
const
ROW_PADDING
=
5
;
const
DEFAULT_CELL_WIDTH
=
9.14
;
const
DEFAULT_ROW_HEIGHT
=
10
;
/**
* Generates a XLS 2007 file and forces the browser to download it.
*
...
...
@@ -18,12 +29,13 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
* See @CRM_Report_Utils_Report::export2csv().
*/
static
function
export2excel2007
(
&
$form
,
&
$rows
)
{
//Force a download and name the file using the current timestamp.
$datetime
=
date
(
'Ymd-Gi'
,
$_SERVER
[
'REQUEST_TIME'
]);
// Force a download and name the file using the current timestamp.
$datetime
=
date
(
'Y-m-d H:i'
);
$filename
=
$form
->
getTitle
()
.
' - '
.
$datetime
.
'.xlsx'
;
header
(
'Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
);
header
(
'Content-Disposition: attachment;filename="
Report_'
.
$dateti
me
.
'
.xlsx
"'
);
header
(
"Content-Description: "
.
ts
(
'CiviCRM report'
)
);
header
(
'Content-Disposition: attachment;filename="
'
.
$filena
me
.
'"'
);
header
(
"Content-Description: "
.
$filename
);
header
(
"Content-Transfer-Encoding: binary"
);
header
(
"Cache-Control: no-cache, must-revalidate, post-check=0, pre-check=0"
);
...
...
@@ -70,12 +82,20 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
// $validLocale = \PhpOffice\PhpSpreadsheet\Settings::setLocale('fr');
// Set document properties
$contact_id
=
CRM_Core_Session
::
singleton
()
->
get
(
'userID'
);
$display_name
=
civicrm_api3
(
'Contact'
,
'getsingle'
,
[
'contact_id'
=>
$contact_id
])[
'display_name'
];
$domain_name
=
CRM_Core_DAO
::
getFieldValue
(
'CRM_Core_DAO_Domain'
,
CRM_Core_Config
::
domainID
(),
'name'
);
$title
=
$form
->
getTitle
();
$objPHPExcel
->
getProperties
()
->
setCreator
(
"CiviCRM"
)
->
setLastModifiedBy
(
"CiviCRM"
)
->
setTitle
(
ts
(
'Report'
))
->
setSubject
(
ts
(
'Report'
))
->
setDescription
(
ts
(
'Report'
));
->
setCreator
(
$display_name
)
->
setLastModifiedBy
(
$display_name
)
->
setTitle
(
$form
->
getTitle
())
->
setDescription
(
E
::
ts
(
'Report exported from CiviCRM (%1) by %2 at %3'
,
[
1
=>
$domain_name
,
2
=>
$display_name
,
3
=>
date
(
'Y-m-d H:i:s'
),
]));
$sheet
=
$objPHPExcel
->
setActiveSheetIndex
(
0
);
$objPHPExcel
->
getActiveSheet
()
->
setTitle
(
'Report'
);
...
...
@@ -90,6 +110,9 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
}
}
// Used for later calculating the column widths
$widths
=
[];
// Add the column headers.
$col
=
0
;
$cpt
=
1
;
...
...
@@ -101,6 +124,8 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
->
setCellValue
(
$cell
,
$h
)
->
getStyle
(
$cell
)
->
applyFromArray
([
'font'
=>
[
'bold'
=>
true
]]);
self
::
addValueLengthToColumnWidths
(
$h
,
$cells
[
$col
],
$widths
);
$col
++
;
}
...
...
@@ -140,6 +165,8 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
$objPHPExcel
->
getActiveSheet
()
->
setCellValue
(
$cells
[
$col
]
.
$cpt
,
$value
);
self
::
addValueLengthToColumnWidths
(
$value
,
$cells
[
$col
],
$widths
);
// Cell formats
if
(
CRM_Utils_Array
::
value
(
'type'
,
$form
->
_columnHeaders
[
$v
])
&
CRM_Utils_Type
::
T_DATE
)
{
$objPHPExcel
->
getActiveSheet
()
...
...
@@ -147,7 +174,7 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
->
getNumberFormat
()
->
setFormatCode
(
\PhpOffice\PhpSpreadsheet\Style\NumberFormat
::
FORMAT_DATE_YYYYMMDD
);
// Set autosize on date columns.
// Set autosize on date columns.
// We only do it for dates because we know they have a fixed width, unlike strings.
// For eco-friendlyness, this should only be done once, perhaps when processing the headers initially
$objPHPExcel
->
getActiveSheet
()
->
getColumnDimension
(
$cells
[
$col
])
->
setAutoSize
(
true
);
...
...
@@ -164,9 +191,173 @@ class CRM_CiviExportExcel_Utils_Report extends CRM_Core_Page {
$cpt
++
;
}
// Re-adjust the column widths
foreach
(
$cells
as
$key
=>
$val
)
{
$w
=
self
::
getRecommendedColumnWidth
(
$val
,
$widths
);
// Ignore width that would be too small to be practical.
if
(
$w
<
5
)
{
continue
;
}
if
(
$w
>
75
)
{
$w
=
75
;
// Ex: A0:A100
$area
=
$val
.
'0:'
.
$val
.
$cpt
;
$objPHPExcel
->
getActiveSheet
()
->
getStyle
(
$area
)
->
getAlignment
()
->
setWrapText
(
true
);
}
$objPHPExcel
->
getActiveSheet
()
->
getColumnDimension
(
$val
)
->
setWidth
(
$w
);
}
// Now set row heights (skip the header)
$sheet
=
$objPHPExcel
->
getActiveSheet
();
for
(
$i
=
2
;
$i
<
$cpt
;
$i
++
)
{
$row
=
new
Row
(
$sheet
,
$i
);
self
::
autofitRowHeight
(
$row
);
}
$objWriter
=
\PhpOffice\PhpSpreadsheet\IOFactory
::
createWriter
(
$objPHPExcel
,
'Xlsx'
);
$objWriter
->
save
(
$filename
);
return
''
;
// FIXME
}
/**
* Helper function to log data widths. Later used by getRecommendedColumnWidth().
* This might be a bit overkill, but worth testing.
*/
static
public
function
addValueLengthToColumnWidths
(
$value
,
$column
,
&
$widths
)
{
$len
=
mb_strlen
(
$value
);
// Ignore empty cells
if
(
!
$len
)
{
return
;
}
if
(
!
isset
(
$widths
[
$column
]))
{
$widths
[
$column
]
=
[];
}
$widths
[
$column
][]
=
$len
;
}
/**
* Returns a recommended column width, based on 90th percentile of rows with data.
*
* Percentile function based on:
* http://php.net/manual/en/function.stats-stat-percentile.php#79752
*/
static
public
function
getRecommendedColumnWidth
(
$column
,
&
$widths
)
{
$p
=
0.9
;
// 90% percentile
if
(
empty
(
$widths
[
$column
]))
{
return
0
;
}
$data
=
$widths
[
$column
];
sort
(
$data
);
$count
=
count
(
$data
);
$allindex
=
(
$count
-
1
)
*
$p
;
$intvalindex
=
intval
(
$allindex
);
$floatval
=
$allindex
-
$intvalindex
;
if
(
!
is_float
(
$floatval
))
{
$result
=
$data
[
$intvalindex
];
}
else
{
if
(
$count
>
$intvalindex
+
1
)
{
$result
=
$floatval
*
(
$data
[
$intvalindex
+
1
]
-
$data
[
$intvalindex
])
+
$data
[
$intvalindex
];
}
else
{
$result
=
$data
[
$intvalindex
];
}
}
// Add a bit of padding.
$result
+=
2
;
return
$result
;
}
/**
* Auto-fit the row height based on the largest cell
*
* Source: https://github.com/PHPOffice/PhpSpreadsheet/issues/333#issuecomment-385943533
*
* @param Row $start
* @return Worksheet
*/
public
static
function
autofitRowHeight
(
Row
$row
,
$rowPadding
=
self
::
ROW_PADDING
)
{
$ws
=
$row
->
getWorksheet
();
$cellIterator
=
$row
->
getCellIterator
();
$cellIterator
->
setIterateOnlyExistingCells
(
true
);
$maxCellLines
=
1
;
/* @var $cell Cell */
foreach
(
$cellIterator
as
$cell
)
{
$cellLength
=
mb_strlen
(
$cell
->
getValue
());
$cellWidth
=
$ws
->
getColumnDimension
(
$cell
->
getParent
()
->
getCurrentColumn
())
->
getWidth
();
// If no column width is set, set the default
if
(
$cellWidth
===
-
1
)
{
// [ML] Let our own function do this
// $ws->getColumnDimension($cell->getParent()->getCurrentColumn())->setWidth(self::DEFAULT_CELL_WIDTH);
$cellWidth
=
$ws
->
getColumnDimension
(
$cell
->
getParent
()
->
getCurrentColumn
())
->
getWidth
();
}
// If the cell is in a merge range we need to determine the full width of the range
if
(
$cell
->
isInMergeRange
())
{
// We only need to do this for the master (first) cell in the range, the rest need to have a line height of 1
if
(
$cell
->
isMergeRangeValueCell
())
{
$mergeRange
=
$cell
->
getMergeRange
();
if
(
$mergeRange
)
{
$mergeWidth
=
0
;
$mergeRefs
=
Coordinate
::
extractAllCellReferencesInRange
(
$mergeRange
);
foreach
(
$mergeRefs
as
$cellRef
)
{
$mergeCell
=
$ws
->
getCell
(
$cellRef
);
$width
=
$ws
->
getColumnDimension
(
$mergeCell
->
getParent
()
->
getCurrentColumn
())
->
getWidth
();
if
(
$width
===
-
1
)
{
// [ML] Let our own function do this
// $ws->getColumnDimension($mergeCell->getParent()->getCurrentColumn())->setWidth(self::DEFAULT_CELL_WIDTH);
$width
=
$ws
->
getColumnDimension
(
$mergeCell
->
getParent
()
->
getCurrentColumn
())
->
getWidth
();
}
$mergeWidth
+=
$width
;
}
$cellWidth
=
$mergeWidth
;
}
else
{
$cellWidth
=
1
;
}
}
else
{
$cellWidth
=
1
;
}
}
// Calculate the number of cell lines with a 10% additional margin
$cellLines
=
ceil
((
$cellLength
*
1.1
)
/
$cellWidth
);
$maxCellLines
=
$cellLines
>
$maxCellLines
?
$cellLines
:
$maxCellLines
;
}
$rowDimension
=
$ws
->
getRowDimension
(
$row
->
getRowIndex
());
$rowHeight
=
$rowDimension
->
getRowHeight
();
// If no row height is set, set the default
if
(
$rowHeight
===
-
1
)
{
$rowDimension
->
setRowHeight
(
self
::
DEFAULT_ROW_HEIGHT
);
$rowHeight
=
$rowDimension
->
getRowHeight
();
}
$rowLines
=
$maxCellLines
<=
0
?
1
:
$maxCellLines
;
$rowDimension
->
setRowHeight
((
$rowHeight
*
$rowLines
)
+
$rowPadding
);
return
$ws
;
}
}
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment