diff --git a/DependencyInjection/Configuration.php b/DependencyInjection/Configuration.php
index 420458e..e86c0c2 100644
--- a/DependencyInjection/Configuration.php
+++ b/DependencyInjection/Configuration.php
@@ -47,6 +47,18 @@ public function getConfigTreeBuilder()
->end()
->end()
->end()
+ ->arrayNode('export')
+ ->addDefaultsIfNotSet()
+ ->children()
+ ->scalarNode('enabled')
+ ->defaultValue(true)
+ ->end()
+ ->scalarNode('path')
+ ->defaultValue('/tmp/')
+ ->end()
+ ->end()
+ ->end()
+ ->end()
->end()
->end()
->end();
diff --git a/Grid/Column.php b/Grid/Column.php
index 616ca49..7b2f9f8 100644
--- a/Grid/Column.php
+++ b/Grid/Column.php
@@ -47,6 +47,11 @@ class Column
*/
protected $renderType = 'text';
+ /**
+ * @var bool
+ */
+ protected $exportOnly = false;
+
/**
* @var \PedroTeixeira\Bundle\GridBundle\Grid\Render\RenderAbstract
*/
@@ -266,6 +271,26 @@ public function getRenderType()
return $this->renderType;
}
+ /**
+ * @param boolean $exportOnly
+ *
+ * @return Column
+ */
+ public function setExportOnly($exportOnly)
+ {
+ $this->exportOnly = $exportOnly;
+
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getExportOnly()
+ {
+ return $this->exportOnly;
+ }
+
/**
* Return render
*
diff --git a/Grid/GridAbstract.php b/Grid/GridAbstract.php
index 0c3cefe..ee44de4 100644
--- a/Grid/GridAbstract.php
+++ b/Grid/GridAbstract.php
@@ -54,6 +54,21 @@ abstract class GridAbstract
*/
protected $ajax;
+ /**
+ * @var bool
+ */
+ protected $exportable;
+
+ /**
+ * @var bool
+ */
+ protected $export;
+
+ /**
+ * @var string
+ */
+ protected $fileHash;
+
/**
* @var string
*/
@@ -79,8 +94,16 @@ public function __construct(\Symfony\Component\DependencyInjection\Container $co
$this->columns = array();
$this->url = null;
+
$this->ajax = $this->request->isXmlHttpRequest() ? true : false;
+ $this->exportable = $this->container->getParameter('pedro_teixeira_grid.export.enabled');
+ $this->export = $this->request->query->get('export', false);
+ $this->fileHash = $this->request->query->get('file_hash', null);
+ if (is_null($this->fileHash)) {
+ $this->fileHash = uniqid();
+ }
+
$now = new \DateTime();
$this->name = md5($now->format('Y-m-d H:i:s:u'));
}
@@ -101,6 +124,22 @@ public function isAjax()
return $this->ajax;
}
+ /**
+ * @return bool Check if it's an export call
+ */
+ public function isExport()
+ {
+ return $this->export;
+ }
+
+ /**
+ * @return bool
+ */
+ public function isResponseAnswer()
+ {
+ return ($this->isAjax() || $this->isExport());
+ }
+
/**
* @param string $name
*
@@ -145,6 +184,26 @@ public function getUrl()
return $this->url;
}
+ /**
+ * @param boolean $exportable
+ *
+ * @return GridAbstract
+ */
+ public function setExportable($exportable)
+ {
+ $this->exportable = $exportable;
+
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getExportable()
+ {
+ return $this->exportable;
+ }
+
/**
* @param \Doctrine\ORM\QueryBuilder $queryBuilder
*
@@ -199,6 +258,17 @@ public function getColumnsCount()
return count($this->getColumns());
}
+ /**
+ * @return string
+ */
+ protected function getExportFileName()
+ {
+ $exportPath = $this->container->getParameter('pedro_teixeira_grid.export.path');
+ $exportFile = $exportPath . $this->getName() . '_' . $this->fileHash . '.csv';
+
+ return $exportFile;
+ }
+
/**
* Process the filters and return the result
*
@@ -253,26 +323,33 @@ public function getData()
$this->getQueryBuilder()->orderBy($sortIndex, $sortOrder);
}
- $totalCount = Paginate::count($this->getQueryBuilder()->getQuery());
+ // Don't process grid for export
+ if (!$this->isExport()) {
+ $totalCount = Paginate::count($this->getQueryBuilder()->getQuery());
- $totalPages = ceil($totalCount / $limit);
- $totalPages = ($totalPages <= 0 ? 1 : $totalPages);
+ $totalPages = ceil($totalCount / $limit);
+ $totalPages = ($totalPages <= 0 ? 1 : $totalPages);
- $page = ($page > $totalPages ? $totalPages : $page);
+ $page = ($page > $totalPages ? $totalPages : $page);
- $queryOffset = (($page * $limit) - $limit);
+ $queryOffset = (($page * $limit) - $limit);
- $this->getQueryBuilder()
- ->setFirstResult($queryOffset)
- ->setMaxResults($limit);
+ $this->getQueryBuilder()
+ ->setFirstResult($queryOffset)
+ ->setMaxResults($limit);
- $response = array(
- 'page' => $page,
- 'page_count' => $totalPages,
- 'page_limit' => $limit,
- 'row_count' => $totalCount,
- 'rows' => array()
- );
+ $response = array(
+ 'page' => $page,
+ 'page_count' => $totalPages,
+ 'page_limit' => $limit,
+ 'row_count' => $totalCount,
+ 'rows' => array()
+ );
+ } else {
+ $response = array(
+ 'rows' => array()
+ );
+ }
foreach ($this->getQueryBuilder()->getQuery()->getResult() as $key => $row) {
@@ -281,6 +358,10 @@ public function getData()
/** @var Column $column */
foreach ($this->columns as $column) {
+ if ($column->getExportOnly() && !$this->isExport()) {
+ continue;
+ }
+
$rowColumn = ' ';
// Array
@@ -316,7 +397,10 @@ public function getData()
);
}
- $rowValue[$column->getField()] = $column->getRender()->setValue($rowColumn)->render();
+ $rowValue[$column->getField()] = $column->getRender()
+ ->setValue($rowColumn)
+ ->setStringOnly($this->isExport())
+ ->render();
}
$response['rows'][$key] = $rowValue;
@@ -325,25 +409,103 @@ public function getData()
return $response;
}
+ /**
+ * @return array
+ */
+ public function processGrid()
+ {
+ return $this->getData();
+ }
+
+ /**
+ * @return array
+ */
+ public function processExport()
+ {
+ set_time_limit(0);
+
+ $exportFile = $this->getExportFileName();
+
+ $fileHandler = fopen($exportFile, 'w');
+
+ $columnsHeader = array();
+
+ /** @var Column $column */
+ foreach ($this->getColumns() as $column) {
+ if (!$column->getTwig()) {
+ $columnsHeader[$column->getField()] = $column->getName();
+ }
+ }
+
+ fputcsv($fileHandler, $columnsHeader);
+
+ $data = $this->getData();
+
+ foreach ($data['rows'] as $row) {
+
+ $rowContent = array();
+
+ foreach ($row as $key => $column) {
+ if (isset($columnsHeader[$key])) {
+ $rowContent[] = $column;
+ }
+ }
+
+ fputcsv($fileHandler, $rowContent);
+ }
+
+ fclose($fileHandler);
+
+ return array(
+ 'file_hash' => $this->fileHash
+ );
+ }
+
/**
* Returns the an array with a GridView instance for normal requests and json for AJAX requests
*
+ * @throws \Exception
* @return GridView | \Symfony\Component\HttpFoundation\Response
*/
public function render()
{
if ($this->isAjax()) {
+ if ($this->isExport()) {
+
+ if (!$this->getExportable()) {
+ throw new \Exception('Export not allowed');
+ }
+
+ $data = $this->processExport();
+ } else {
+ $data = $this->processGrid();
+ }
- $data = $this->getData();
$json = json_encode($data);
$response = new Response();
- $response->setContent($json);
$response->headers->set('Content-Type', 'application/json');
+ $response->setContent($json);
return $response;
} else {
- return new GridView($this, $this->container);
+ if ($this->isExport()) {
+
+ if (!$this->getExportable()) {
+ throw new \Exception('Export not allowed');
+ }
+
+ $exportFile = $this->getExportFileName();
+
+ $response = new Response();
+ $response->headers->set('Content-Type', 'text/csv');
+ $response->headers->set('Content-Disposition', 'attachment; filename="' . basename($exportFile) . '"');
+ $response->setContent(file_get_contents($exportFile));
+
+ return $response;
+ } else {
+ return new GridView($this, $this->container);
+ }
}
}
}
\ No newline at end of file
diff --git a/Grid/Render/RenderAbstract.php b/Grid/Render/RenderAbstract.php
index 093a612..e4bdd92 100644
--- a/Grid/Render/RenderAbstract.php
+++ b/Grid/Render/RenderAbstract.php
@@ -17,6 +17,11 @@ abstract class RenderAbstract
*/
protected $value;
+ /**
+ * @var bool
+ */
+ protected $stringOnly = false;
+
/**
* @return string
*/
@@ -25,7 +30,7 @@ abstract public function render();
/**
* @param \Symfony\Component\DependencyInjection\Container $container
*
- * @return \PedroTeixeira\Bundle\GridBundle\Grid\Filter\RenderAbstract
+ * @return \PedroTeixeira\Bundle\GridBundle\Grid\Render\RenderAbstract
*/
public function __construct(\Symfony\Component\DependencyInjection\Container $container)
{
@@ -51,4 +56,24 @@ public function getValue()
{
return $this->value;
}
+
+ /**
+ * @param boolean $stringOnly
+ *
+ * @return RenderAbstract
+ */
+ public function setStringOnly($stringOnly)
+ {
+ $this->stringOnly = $stringOnly;
+
+ return $this;
+ }
+
+ /**
+ * @return boolean
+ */
+ public function getStringOnly()
+ {
+ return $this->stringOnly;
+ }
}
\ No newline at end of file
diff --git a/Grid/Render/Url.php b/Grid/Render/Url.php
index 53a7931..7e2ee28 100644
--- a/Grid/Render/Url.php
+++ b/Grid/Render/Url.php
@@ -12,6 +12,10 @@ class Url extends RenderAbstract
*/
public function render()
{
- return '' . $this->getValue() . '';
+ if ($this->getStringOnly()) {
+ return $this->getValue();
+ } else {
+ return '' . $this->getValue() . '';
+ }
}
}
\ No newline at end of file
diff --git a/Grid/Render/YesNo.php b/Grid/Render/YesNo.php
index 0d7de31..313d41f 100644
--- a/Grid/Render/YesNo.php
+++ b/Grid/Render/YesNo.php
@@ -22,10 +22,14 @@ class YesNo extends RenderAbstract
*/
public function render()
{
- if ($this->getValue() && $this->getShowYes()) {
- return '';
- } else if ($this->getShowNo()) {
- return '';
+ if ($this->getStringOnly()) {
+ return (int) $this->getValue();
+ } else {
+ if ($this->getValue() && $this->getShowYes()) {
+ return '';
+ } else if ($this->getShowNo()) {
+ return '';
+ }
}
return null;
diff --git a/README.md b/README.md
index 9299c95..1573ac7 100644
--- a/README.md
+++ b/README.md
@@ -9,9 +9,9 @@ Requirements
1. [Doctrine Extensions](https://github.com/beberlei/DoctrineExtensions)
2. [Twitter Bootstrap](http://twitter.github.com/bootstrap/) (not mandatory)
- * If you choose to don't use Twitter Bootstrap, it'll be necessary to create your own style.
+ * If you choose to don't use Twitter Bootstrap, it'll be necessary to create your own style.
3. [jQuery Bootstrap Datepicker](http://www.eyecon.ro/bootstrap-datepicker/) (not mandatory)
- * If you choose to don't use Bootstrap Datepicker, please disable the datepicker as default in the configuration, "use_datepicker".
+ * If you choose to don't use Bootstrap Datepicker, please disable the datepicker as default in the configuration, "use_datepicker".
Installation
@@ -65,19 +65,22 @@ Installation
5. **(optional) Adjust configurations**
- ```yml
- # application/config/config.yml
- pedro_teixeira_grid:
- defaults:
- date:
- use_datepicker: true
- date_format: 'dd/MM/yy'
- date_time_format: 'dd/MM/yy HH:mm:ss'
- pagination:
- limit: 20
- ```
-
- The configuration "use_datepicker" will set the input type as "text" and attach a jQuery plugin "datepicker()" to the filter.
+ ```yml
+ # application/config/config.yml
+ pedro_teixeira_grid:
+ defaults:
+ date:
+ use_datepicker: true
+ date_format: 'dd/MM/yy'
+ date_time_format: 'dd/MM/yy HH:mm:ss'
+ pagination:
+ limit: 20
+ export:
+ enabled true
+ path: '/tmp/'
+ ```
+
+ The configuration "use_datepicker" will set the input type as "text" and attach a jQuery plugin "datepicker()" to the filter.
Create your grid
@@ -104,6 +107,11 @@ Create your grid
*/
public function setupGrid()
{
+ $this->addColumn('Hidden Field')
+ ->setField('hidden')
+ ->setIndex('r.hidden')
+ ->setExportOnly(true);
+
$this->addColumn('ID')
->setField('id')
->setIndex('r.id')
@@ -172,7 +180,7 @@ Create your grid
$grid = $this->get('pedroteixeira.grid')->createGrid('\PedroTeixeira\Bundle\TestBundle\Grid\TestGrid');
$grid->setQueryBuilder($queryBuilder);
- if ($grid->isAjax()) {
+ if ($grid->isResponseAnswer()) {
return $grid->render();
}
diff --git a/Resources/doc/column.md b/Resources/doc/column.md
index ca83336..309dc47 100644
--- a/Resources/doc/column.md
+++ b/Resources/doc/column.md
@@ -84,6 +84,27 @@ public function setupGrid()
}
```
+protected $exportOnly
+------------
+
+Just show the field in the export.
+
+Default:
+
+```
+false
+```
+
+Usage:
+
+```php
+public function setupGrid()
+{
+ $this->addColumn()
+ ->setExportOnly(true);
+}
+```
+
protected $filterType
------------
diff --git a/Resources/doc/grid.md b/Resources/doc/grid.md
index 90da0b0..d582b5e 100644
--- a/Resources/doc/grid.md
+++ b/Resources/doc/grid.md
@@ -24,6 +24,22 @@ Usage:
$grid->setName('My Grid');
```
+protected $exportable
+------------
+Enable export in the grid.
+
+Default:
+
+```
+true
+```
+
+Usage:
+
+```php
+$grid->setExportable(false);
+```
+
abstract public function setupGrid()
------------
Use this method to define your grid.
diff --git a/Resources/public/js/grid.js b/Resources/public/js/grid.js
index 5d68438..9da23d9 100644
--- a/Resources/public/js/grid.js
+++ b/Resources/public/js/grid.js
@@ -41,16 +41,22 @@
'limit':this.limit,
'sort': this.sortIndex,
'sort_order': this.sortOrder,
- 'export': this.exportFlag,
+ 'export': (this.exportFlag ? 1 : 0),
'filters': filters
},
dataType:'json',
+ timeout: (this.exportFlag ? (5*60*1000) : (10 * 1000)),
beforeSend:function (data) {
thisClass.gridLock()
},
success:function (data) {
thisClass.gridUnlock()
+ if (data.file_hash) {
+ window.location = thisClass.ajaxUrl + '?export=1&file_hash=' + data.file_hash
+ return
+ }
+
thisClass.page = data.page
thisClass.limit = data.page_limit
thisClass.totalRows = data.row_count
@@ -131,6 +137,7 @@
, export:function () {
this.exportFlag = true
this.ajax()
+ this.exportFlag = false
return this
}
diff --git a/Resources/views/block.html.twig b/Resources/views/block.html.twig
index 92fcba8..7cc6236 100644
--- a/Resources/views/block.html.twig
+++ b/Resources/views/block.html.twig
@@ -6,12 +6,16 @@
{% for column in view.grid.columns %}
-
{{ column.name }}
+ {% if column.exportOnly == false %}
+ {{ column.name }}
+ {% endif %}
{% endfor %}
{% for column in view.grid.columns %}
-
@@ -33,10 +37,11 @@
{% trans %}Refresh Filters{% endtrans %}
- {# @todo Implement #}
- {##}
+ {% if view.grid.exportable %}
+
+ {% endif %}
{{ column.renderFilter | raw }}
+ {% if column.exportOnly == false %}
+ {{ column.renderFilter | raw }}
+ {% endif %}
{% endfor %}