';
}
diff --git a/Grid/Export/Export.php b/Grid/Export/Export.php
index 4f5d5b91..b4c058e7 100644
--- a/Grid/Export/Export.php
+++ b/Grid/Export/Export.php
@@ -12,13 +12,16 @@
namespace APY\DataGridBundle\Grid\Export;
-use Symfony\Component\DependencyInjection\ContainerAwareInterface;
+use APY\DataGridBundle\Grid\Column\ArrayColumn;
+use APY\DataGridBundle\Grid\Grid;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Symfony\Component\HttpFoundation\Response;
+use Twig\TemplateWrapper;
+use Twig\Environment;
abstract class Export implements ExportInterface, ContainerAwareInterface
{
- const DEFAULT_TEMPLATE = 'APYDataGridBundle::blocks.html.twig';
+ const DEFAULT_TEMPLATE = '@APYDataGrid/blocks.html.twig';
protected $title;
@@ -28,7 +31,7 @@ abstract class Export implements ExportInterface, ContainerAwareInterface
protected $mimeType = 'application/octet-stream';
- protected $parameters = array();
+ protected $parameters = [];
protected $container;
@@ -38,7 +41,7 @@ abstract class Export implements ExportInterface, ContainerAwareInterface
protected $grid;
- protected $params = array();
+ protected $params = [];
protected $content;
@@ -47,17 +50,17 @@ abstract class Export implements ExportInterface, ContainerAwareInterface
protected $role;
/**
- * Default Export constructor
+ * Default Export constructor.
*
- * @param string $title Title of the export
+ * @param string $title Title of the export
* @param string $fileName FileName of the export
- * @param array $parameters Additionnal parameters for the export
- * @param string $charset Charset of the exported data
- * @param string $role Security role
+ * @param array $params Additionnal parameters for the export
+ * @param string $charset Charset of the exported data
+ * @param string $role Security role
*
* @return \APY\DataGridBundle\Grid\Export\Export
*/
- public function __construct($title, $fileName = 'export', $params = array(), $charset = 'UTF-8', $role = null)
+ public function __construct($title, $fileName = 'export', $params = [], $charset = 'UTF-8', $role = null)
{
$this->title = $title;
$this->fileName = $fileName;
@@ -70,16 +73,20 @@ public function __construct($title, $fileName = 'export', $params = array(), $ch
* Sets the Container associated with this Controller.
*
* @param ContainerInterface $container A ContainerInterface instance
+ *
+ * @return \APY\DataGridBundle\Grid\Export\Export
*/
public function setContainer(ContainerInterface $container = null)
{
$this->container = $container;
- $this->twig = $this->container->get('twig');
-
return $this;
}
+ public function setTwig(Environment $twig)
+ {
+ $this->twig = $twig;
+ }
/**
* gets the Container associated with this Controller.
*
@@ -91,11 +98,11 @@ public function getContainer()
}
/**
- * gets the export Response
+ * gets the export Response.
*
* @return Response
*/
- public function getResponse()
+ public function getResponse() : \Symfony\Component\HttpFoundation\Response
{
// Response
$kernelCharset = $this->container->getParameter('kernel.charset');
@@ -107,15 +114,15 @@ public function getResponse()
$this->charset = $kernelCharset;
}
- $headers = array(
- 'Content-Description' => 'File Transfer',
- 'Content-Type' => $this->getMimeType(),
- 'Content-Disposition' => sprintf('attachment; filename="%s"', $this->getBaseName()),
+ $headers = [
+ 'Content-Description' => 'File Transfer',
+ 'Content-Type' => $this->getMimeType(),
+ 'Content-Disposition' => sprintf('attachment; filename="%s"', $this->getBaseName()),
'Content-Transfer-Encoding' => 'binary',
- 'Cache-Control' => 'must-revalidate',
- 'Pragma' => 'public',
- 'Content-Length' => $filesize
- );
+ 'Cache-Control' => 'must-revalidate',
+ 'Pragma' => 'public',
+ 'Content-Length' => $filesize,
+ ];
$response = new Response($this->content, 200, $headers);
$response->setCharset($this->charset);
@@ -125,7 +132,7 @@ public function getResponse()
}
/**
- * sets the Content of the export
+ * sets the Content of the export.
*
* @param string $content
*
@@ -139,7 +146,7 @@ public function setContent($content = '')
}
/**
- * gets the Content of the export
+ * gets the Content of the export.
*
* @return string
*/
@@ -149,7 +156,7 @@ public function getContent()
}
/**
- * Get data form the grid
+ * Get data form the grid.
*
* @param Grid $grid
*
@@ -174,7 +181,7 @@ public function getContent()
*/
protected function getGridData($grid)
{
- $result = array();
+ $result = [];
$this->grid = $grid;
@@ -189,7 +196,7 @@ protected function getGridData($grid)
protected function getRawGridData($grid)
{
- $result = array();
+ $result = [];
$this->grid = $grid;
if ($this->grid->isTitleSectionVisible()) {
@@ -202,7 +209,7 @@ protected function getRawGridData($grid)
}
/**
- * Get data form the grid in a flat array
+ * Get data form the grid in a flat array.
*
* @param Grid $grid
*
@@ -227,7 +234,7 @@ protected function getFlatGridData($grid)
{
$data = $this->getGridData($grid);
- $flatData = array();
+ $flatData = [];
if (isset($data['titles'])) {
$flatData[] = $data['titles'];
}
@@ -239,7 +246,7 @@ protected function getFlatRawGridData($grid)
{
$data = $this->getRawGridData($grid);
- $flatData = array();
+ $flatData = [];
if (isset($data['titles'])) {
$flatData[] = $data['titles'];
}
@@ -249,7 +256,7 @@ protected function getFlatRawGridData($grid)
protected function getGridTitles()
{
- $titlesHTML = $this->renderBlock('grid_titles', array('grid' => $this->grid));
+ $titlesHTML = $this->renderBlock('grid_titles', ['grid' => $this->grid]);
preg_match_all('#
]*?>(.*)?
#isU', $titlesHTML, $matches);
@@ -261,10 +268,11 @@ protected function getGridTitles()
new \Exception('Table header (th or td) tags not found.');
}
- $titlesClean = array_map(array($this, 'cleanHTML'), $matches[0]);
+ $titlesClean = array_map([$this, 'cleanHTML'], $matches[0]);
$i = 0;
- $titles = array();
+ $titles = [];
+
foreach ($this->grid->getColumns() as $column) {
if ($column->isVisible(true)) {
if (!isset($titlesClean[$i])) {
@@ -281,10 +289,10 @@ protected function getRawGridTitles()
{
$translator = $this->container->get('translator');
- $titles = array();
+ $titles = [];
foreach ($this->grid->getColumns() as $column) {
if ($column->isVisible(true)) {
- $titles[] = utf8_decode($translator->trans(/** @Ignore */$column->getTitle()));
+ $titles[] = utf8_decode($translator->trans(/* @Ignore */$column->getTitle()));
}
}
@@ -293,7 +301,7 @@ protected function getRawGridTitles()
protected function getGridRows()
{
- $rows = array();
+ $rows = [];
foreach ($this->grid->getRows() as $i => $row) {
foreach ($this->grid->getColumns() as $column) {
if ($column->isVisible(true)) {
@@ -308,7 +316,7 @@ protected function getGridRows()
protected function getRawGridRows()
{
- $rows = array();
+ $rows = [];
foreach ($this->grid->getRows() as $i => $row) {
foreach ($this->grid->getColumns() as $column) {
if ($column->isVisible(true)) {
@@ -322,53 +330,65 @@ protected function getRawGridRows()
protected function getGridCell($column, $row)
{
+ $values = $row->getField($column->getId());
+
// Cast a datetime won't work.
- if (!is_array($values = $row->getField($column->getId()))) {
- $values = array($values);
+ if ($column instanceof ArrayColumn || !is_array($values)) {
+ $values = [$values];
}
+ $separator = $column->getSeparator();
+
$block = null;
- $return = array();
+ $return = [];
foreach ($values as $sourceValue) {
$value = $column->renderCell($sourceValue, $row, $this->container->get('router'));
$id = $this->grid->getId();
if (($id != '' && ($block !== null
- || $this->hasBlock($block = 'grid_'.$id.'_column_'.$column->getRenderBlockId().'_cell')
- || $this->hasBlock($block = 'grid_'.$id.'_column_'.$column->getType().'_cell')
- || $this->hasBlock($block = 'grid_'.$id.'_column_'.$column->getParentType().'_cell')))
- || $this->hasBlock($block = 'grid_'.$id.'_column_id_'.$column->getRenderBlockId().'_cell')
- || $this->hasBlock($block = 'grid_'.$id.'_column_type_'.$column->getType().'_cell')
- || $this->hasBlock($block = 'grid_'.$id.'_column_type_'.$column->getParentType().'_cell')
- || $this->hasBlock($block = 'grid_column_'.$column->getRenderBlockId().'_cell')
- || $this->hasBlock($block = 'grid_column_'.$column->getType().'_cell')
- || $this->hasBlock($block = 'grid_column_'.$column->getParentType().'_cell')
- || $this->hasBlock($block = 'grid_column_id_'.$column->getRenderBlockId().'_cell')
- || $this->hasBlock($block = 'grid_column_type_'.$column->getType().'_cell')
- || $this->hasBlock($block = 'grid_column_type_'.$column->getParentType().'_cell'))
- {
- $return[] = $this->renderBlock($block, array('grid' => $this->grid, 'column' => $column, 'row' => $row, 'value' => $value, 'sourceValue' => $sourceValue));
+ || $this->hasBlock($block = 'grid_' . $id . '_column_' . $column->getRenderBlockId() . '_cell')
+ || $this->hasBlock($block = 'grid_' . $id . '_column_' . $column->getType() . '_cell')
+ || $this->hasBlock($block = 'grid_' . $id . '_column_' . $column->getParentType() . '_cell')))
+ || $this->hasBlock($block = 'grid_' . $id . '_column_id_' . $column->getRenderBlockId() . '_cell')
+ || $this->hasBlock($block = 'grid_' . $id . '_column_type_' . $column->getType() . '_cell')
+ || $this->hasBlock($block = 'grid_' . $id . '_column_type_' . $column->getParentType() . '_cell')
+ || $this->hasBlock($block = 'grid_column_' . $column->getRenderBlockId() . '_cell')
+ || $this->hasBlock($block = 'grid_column_' . $column->getType() . '_cell')
+ || $this->hasBlock($block = 'grid_column_' . $column->getParentType() . '_cell')
+ || $this->hasBlock($block = 'grid_column_id_' . $column->getRenderBlockId() . '_cell')
+ || $this->hasBlock($block = 'grid_column_type_' . $column->getType() . '_cell')
+ || $this->hasBlock($block = 'grid_column_type_' . $column->getParentType() . '_cell')) {
+ $html = $this->renderBlock($block, ['grid' => $this->grid, 'column' => $column, 'row' => $row, 'value' => $value, 'sourceValue' => $sourceValue]);
} else {
- $return[] = $this->renderBlock('grid_column_cell', array('grid' => $this->grid, 'column' => $column, 'row' => $row, 'value' => $value, 'sourceValue' => $sourceValue));
+ $html = $this->renderBlock('grid_column_cell', ['grid' => $this->grid, 'column' => $column, 'row' => $row, 'value' => $value, 'sourceValue' => $sourceValue]);
$block = null;
}
+ // Fix blank separator. The will be removed by the HTML cleaner.
+ if (false !== strpos($separator, 'br')) {
+ $html = str_replace($separator, ',', $html);
+ }
+
+ $return[] = $html;
}
- return implode($column->getSeparator() , $return);
+ $value = implode($separator, $return);
+
+ return $value;
}
/**
- * Has block
+ * Has block.
*
* @param $name string
- * @return boolean
+ *
+ * @return bool
*/
protected function hasBlock($name)
{
foreach ($this->getTemplates() as $template) {
- if ($template->hasBlock($name)) {
+ if ($template->hasBlock($name, [])) {
return true;
}
}
@@ -377,16 +397,17 @@ protected function hasBlock($name)
}
/**
- * Render block
+ * Render block.
*
* @param $name string
* @param $parameters string
+ *
* @return string
*/
protected function renderBlock($name, $parameters)
{
foreach ($this->getTemplates() as $template) {
- if ($template->hasBlock($name)) {
+ if ($template->hasBlock($name, [])) {
return $template->renderBlock($name, array_merge($parameters, $this->params));
}
}
@@ -395,10 +416,11 @@ protected function renderBlock($name, $parameters)
}
/**
- * Template Loader
+ * Template Loader.
*
- * @return \Twig_TemplateInterface[]
* @throws \Exception
+ *
+ * @return \Twig_TemplateInterface[]
*/
protected function getTemplates()
{
@@ -410,23 +432,25 @@ protected function getTemplates()
}
/**
- * set template
+ * set template.
*
* @param \Twig_TemplateInterface|string $template
*
- * @return self
+ * @throws \Exception
+ *
+ * @return \APY\DataGridBundle\Grid\Export\Export
*/
public function setTemplate($template)
{
if (is_string($template)) {
if (substr($template, 0, 8) === '__SELF__') {
$this->templates = $this->getTemplatesFromString(substr($template, 8));
- $this->templates[] = $this->twig->loadTemplate(static::DEFAULT_TEMPLATE);
+ $this->templates[] = $this->twig->load(static::DEFAULT_TEMPLATE);
} else {
$this->templates = $this->getTemplatesFromString($template);
}
} elseif ($this->templates === null) {
- $this->templates[] = $this->twig->loadTemplate(static::DEFAULT_TEMPLATE);
+ $this->templates[] = $this->twig->load(static::DEFAULT_TEMPLATE);
} else {
throw new \Exception('Unable to load template');
}
@@ -436,14 +460,11 @@ public function setTemplate($template)
protected function getTemplatesFromString($theme)
{
- $templates = array();
-
- $template = $this->twig->loadTemplate($theme);
- while ($template != null) {
+ $templates = [];
+ $template = $this->twig->load($theme);
+ if ($template instanceof TemplateWrapper) {
$templates[] = $template;
- $template = $template->getParent(array());
}
-
return $templates;
}
@@ -461,6 +482,12 @@ protected function cleanHTML($value)
// Convert Special Characters in HTML
$value = html_entity_decode($value, ENT_QUOTES);
+ // Remove whitespace
+ $value = preg_replace('/\s\s+/', ' ', $value);
+
+ // Fix space
+ $value = preg_replace('/\s,/', ',', $value);
+
// Trim
$value = trim($value);
@@ -468,7 +495,7 @@ protected function cleanHTML($value)
}
/**
- * set title
+ * set title.
*
* @param string $title
*
@@ -482,17 +509,17 @@ public function setTitle($title)
}
/**
- * get title
+ * get title.
*
* @return string
*/
- public function getTitle()
+ public function getTitle() : string
{
return $this->title;
}
/**
- * set file name
+ * set file name.
*
* @param string $fileName
*
@@ -506,7 +533,7 @@ public function setFileName($fileName)
}
/**
- * get file name
+ * get file name.
*
* @return string
*/
@@ -516,7 +543,7 @@ public function getFileName()
}
/**
- * set file extension
+ * set file extension.
*
* @param string $fileExtension
*
@@ -530,7 +557,7 @@ public function setFileExtension($fileExtension)
}
/**
- * get file extension
+ * get file extension.
*
* @return string
*/
@@ -540,17 +567,17 @@ public function getFileExtension()
}
/**
- * get base name
+ * get base name.
*
* @return string
*/
public function getBaseName()
{
- return $this->fileName.(isset($this->fileExtension) ? ".$this->fileExtension" : '');
+ return $this->fileName . (isset($this->fileExtension) ? ".$this->fileExtension" : '');
}
/**
- * set response mime type
+ * set response mime type.
*
* @param string $mimeType
*
@@ -564,7 +591,7 @@ public function setMimeType($mimeType)
}
/**
- * get response mime type
+ * get response mime type.
*
* @return string
*/
@@ -574,7 +601,7 @@ public function getMimeType()
}
/**
- * set response charset
+ * set response charset.
*
* @param string $charset
*
@@ -588,7 +615,7 @@ public function setCharset($charset)
}
/**
- * get response charset
+ * get response charset.
*
* @return string
*/
@@ -598,7 +625,7 @@ public function getCharset()
}
/**
- * set parameters
+ * set parameters.
*
* @param array $parameters
*
@@ -611,8 +638,8 @@ public function setParameters(array $parameters)
return $this;
}
- /**
- * get parameters
+ /**
+ * get parameters.
*
* @return array
*/
@@ -621,8 +648,8 @@ public function getParameters()
return $this->parameters;
}
- /**
- * has parameter
+ /**
+ * has parameter.
*
* @return mixed
*/
@@ -632,11 +659,12 @@ public function hasParameter($name)
}
/**
- * add parameter
+ * add parameter.
*
- * @param array $template
+ * @param $name
+ * @param $value
*
- * @return self
+ * @return \APY\DataGridBundle\Grid\Export\Export
*/
public function addParameter($name, $value)
{
@@ -646,13 +674,13 @@ public function addParameter($name, $value)
}
/**
- * get parameter
+ * get parameter.
*
* @return mixed
*/
public function getParameter($name)
{
- if (!hasParameter($name)) {
+ if (!$this->hasParameter($name)) {
throw new \InvalidArgumentException(sprintf('The parameter "%s" must be defined.', $name));
}
@@ -660,7 +688,7 @@ public function getParameter($name)
}
/**
- * set role
+ * set role.
*
* @param mixed $role
*
@@ -674,7 +702,7 @@ public function setRole($role)
}
/**
- * Get role
+ * Get role.
*
* @return mixed
*/
diff --git a/Grid/Export/ExportInterface.php b/Grid/Export/ExportInterface.php
index 68de8b7a..8e0b5314 100644
--- a/Grid/Export/ExportInterface.php
+++ b/Grid/Export/ExportInterface.php
@@ -12,31 +12,34 @@
namespace APY\DataGridBundle\Grid\Export;
+use APY\DataGridBundle\Grid\Grid;
+use Symfony\Component\HttpFoundation\Response;
+
interface ExportInterface
{
/**
- * function call by the grid to fill the content of the export
+ * function call by the grid to fill the content of the export.
*
* @param Grid $grid The grid
*/
- public function computeData($grid);
+ public function computeData(Grid $grid);
/**
- * Get the export Response
+ * Get the export Response.
*
* @return Response
*/
- public function getResponse();
+ public function getResponse(): Response;
/**
- * Get the export title
+ * Get the export title.
*
* @return string
*/
- public function getTitle();
+ public function getTitle(): string;
/**
- * Get the export role
+ * Get the export role.
*
* @return mixed
*/
diff --git a/Grid/Export/JSONExport.php b/Grid/Export/JSONExport.php
index 8397831d..df6e30b7 100644
--- a/Grid/Export/JSONExport.php
+++ b/Grid/Export/JSONExport.php
@@ -12,14 +12,16 @@
namespace APY\DataGridBundle\Grid\Export;
+use APY\DataGridBundle\Grid\Grid;
+
/**
- * JSON
+ * JSON.
*/
class JSONExport extends Export
{
protected $fileExtension = 'json';
- public function computeData($grid)
+ public function computeData(Grid $grid)
{
$this->content = json_encode($this->getGridData($grid));
}
diff --git a/Grid/Export/PHPExcel2003Export.php b/Grid/Export/PHPExcel2003Export.php
index 234737dc..2f5d5804 100644
--- a/Grid/Export/PHPExcel2003Export.php
+++ b/Grid/Export/PHPExcel2003Export.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * PHPExcel_Excel 2003 Export (.xlsx)
+ * PHPExcel_Excel 2003 Export (.xlsx).
*/
class PHPExcel2003Export extends PHPExcel2007Export
{
diff --git a/Grid/Export/PHPExcel2007Export.php b/Grid/Export/PHPExcel2007Export.php
index dafcd9d0..eafea087 100644
--- a/Grid/Export/PHPExcel2007Export.php
+++ b/Grid/Export/PHPExcel2007Export.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * PHPExcel 2007 Export
+ * PHPExcel 2007 Export.
*/
class PHPExcel2007Export extends PHPExcel5Export
{
diff --git a/Grid/Export/PHPExcel5Export.php b/Grid/Export/PHPExcel5Export.php
index 5ab9f18b..9732be7b 100644
--- a/Grid/Export/PHPExcel5Export.php
+++ b/Grid/Export/PHPExcel5Export.php
@@ -1,6 +1,6 @@
@@ -12,9 +12,11 @@
namespace APY\DataGridBundle\Grid\Export;
+use APY\DataGridBundle\Grid\Grid;
+
/**
* PHPExcel 5 Export (97-2003) (.xls)
- * 52 columns maximum
+ * 52 columns maximum.
*/
class PHPExcel5Export extends Export
{
@@ -24,14 +26,14 @@ class PHPExcel5Export extends Export
public $objPHPExcel;
- public function __construct($tilte, $fileName = 'export', $params = array(), $charset = 'UTF-8')
+ public function __construct($tilte, $fileName = 'export', $params = [], $charset = 'UTF-8')
{
- $this->objPHPExcel = new \PHPExcel();
+ $this->objPHPExcel = new \PHPExcel();
parent::__construct($tilte, $fileName, $params, $charset);
}
- public function computeData($grid)
+ public function computeData(Grid $grid)
{
$data = $this->getFlatGridData($grid);
@@ -39,18 +41,18 @@ public function computeData($grid)
foreach ($data as $line) {
$column = 'A';
foreach ($line as $cell) {
- $this->objPHPExcel->getActiveSheet()->SetCellValue($column.$row, $cell);
+ $this->objPHPExcel->getActiveSheet()->SetCellValue($column . $row, $cell);
- $column++;
+ ++$column;
}
- $row++;
+ ++$row;
}
$objWriter = $this->getWriter();
ob_start();
- $objWriter->save("php://output");
+ $objWriter->save('php://output');
$this->content = ob_get_contents();
diff --git a/Grid/Export/PHPExcelHTMLExport.php b/Grid/Export/PHPExcelHTMLExport.php
index 09b6138b..911e1810 100644
--- a/Grid/Export/PHPExcelHTMLExport.php
+++ b/Grid/Export/PHPExcelHTMLExport.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * PHPExcel HTML Export
+ * PHPExcel HTML Export.
*/
class PHPExcelHTMLExport extends PHPExcel5Export
{
diff --git a/Grid/Export/PHPExcelPDFExport.php b/Grid/Export/PHPExcelPDFExport.php
index 3d5e964e..c71017d5 100644
--- a/Grid/Export/PHPExcelPDFExport.php
+++ b/Grid/Export/PHPExcelPDFExport.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * PHPExcel PDF Export
+ * PHPExcel PDF Export.
*/
class PHPExcelPDFExport extends PHPExcel5Export
{
diff --git a/Grid/Export/SCSVExport.php b/Grid/Export/SCSVExport.php
index ab6c03a3..b0685269 100644
--- a/Grid/Export/SCSVExport.php
+++ b/Grid/Export/SCSVExport.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * Semi-Colon-Separated Values
+ * Semi-Colon-Separated Values.
*/
class SCSVExport extends CSVExport
{
diff --git a/Grid/Export/TSVExport.php b/Grid/Export/TSVExport.php
index e41d89d2..463d3c8f 100644
--- a/Grid/Export/TSVExport.php
+++ b/Grid/Export/TSVExport.php
@@ -13,7 +13,7 @@
namespace APY\DataGridBundle\Grid\Export;
/**
- * Tab-Separated Values
+ * Tab-Separated Values.
*/
class TSVExport extends DSVExport
{
diff --git a/Grid/Export/XMLExport.php b/Grid/Export/XMLExport.php
index 2710f83c..3e325c53 100644
--- a/Grid/Export/XMLExport.php
+++ b/Grid/Export/XMLExport.php
@@ -12,12 +12,13 @@
namespace APY\DataGridBundle\Grid\Export;
-use Symfony\Component\Serializer\Serializer;
-use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
+use APY\DataGridBundle\Grid\Grid;
use Symfony\Component\Serializer\Encoder\XmlEncoder;
+use Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer;
+use Symfony\Component\Serializer\Serializer;
/**
- * XML
+ * XML.
*/
class XMLExport extends Export
{
@@ -25,17 +26,21 @@ class XMLExport extends Export
protected $mimeType = 'application/xml';
- public function computeData($grid)
+ public function computeData(Grid $grid)
{
- $xmlEncoder = new XmlEncoder();
- $xmlEncoder->setRootNodeName('grid');
- $serializer = new Serializer(array(new GetSetMethodNormalizer()), array('xml' => $xmlEncoder));
+ if (defined(XmlEncoder::class.'::ROOT_NODE_NAME')) {
+ $xmlEncoder = new XmlEncoder([XmlEncoder::ROOT_NODE_NAME => 'grid']);
+ } else {
+ $xmlEncoder = new XmlEncoder();
+ $xmlEncoder->setRootNodeName('grid');
+ }
+ $serializer = new Serializer([new GetSetMethodNormalizer()], [XmlEncoder::FORMAT => $xmlEncoder]);
$data = $this->getGridData($grid);
$convertData['titles'] = $data['titles'];
$convertData['rows']['row'] = $data['rows'];
- $this->content = $serializer->serialize($convertData, 'xml');
+ $this->content = $serializer->serialize($convertData, XmlEncoder::FORMAT);
}
}
diff --git a/Grid/Filter.php b/Grid/Filter.php
index eaef9fd6..5f189c36 100644
--- a/Grid/Filter.php
+++ b/Grid/Filter.php
@@ -18,6 +18,11 @@ class Filter
protected $operator;
protected $columnName;
+ /**
+ * @param string $operator
+ * @param mixed|null $value
+ * @param string|null $columnName
+ */
public function __construct($operator, $value = null, $columnName = null)
{
$this->value = $value;
@@ -25,6 +30,11 @@ public function __construct($operator, $value = null, $columnName = null)
$this->columnName = $columnName;
}
+ /**
+ * @param string $operator
+ *
+ * @return Filter
+ */
public function setOperator($operator)
{
$this->operator = $operator;
@@ -32,11 +42,19 @@ public function setOperator($operator)
return $this;
}
+ /**
+ * @return string
+ */
public function getOperator()
{
return $this->operator;
}
+ /**
+ * @param mixed $value
+ *
+ * @return Filter
+ */
public function setValue($value)
{
$this->value = $value;
@@ -44,16 +62,27 @@ public function setValue($value)
return $this;
}
+ /**
+ * @return mixed|null
+ */
public function getValue()
{
return $this->value;
}
+ /**
+ * @return bool
+ */
public function hasColumnName()
{
return $this->columnName !== null;
}
+ /**
+ * @param string $columnName
+ *
+ * @return Filter
+ */
public function setColumnName($columnName)
{
$this->columnName = $columnName;
@@ -61,6 +90,9 @@ public function setColumnName($columnName)
return $this;
}
+ /**
+ * @return string|null
+ */
public function getColumnName()
{
return $this->columnName;
diff --git a/Grid/Grid.php b/Grid/Grid.php
index f7a52731..e59949ef 100644
--- a/Grid/Grid.php
+++ b/Grid/Grid.php
@@ -13,32 +13,59 @@
namespace APY\DataGridBundle\Grid;
-use Symfony\Component\HttpFoundation\RedirectResponse;
-use Symfony\Component\HttpFoundation\Response;
-use Symfony\Component\DependencyInjection\ContainerAwareInterface;
-
use APY\DataGridBundle\Grid\Action\MassActionInterface;
use APY\DataGridBundle\Grid\Action\RowActionInterface;
+use APY\DataGridBundle\Grid\Column\ActionsColumn;
use APY\DataGridBundle\Grid\Column\Column;
use APY\DataGridBundle\Grid\Column\MassActionColumn;
-use APY\DataGridBundle\Grid\Column\ActionsColumn;
-use APY\DataGridBundle\Grid\Source\Source;
+use APY\DataGridBundle\Grid\Export\ContainerAwareInterface;
+use APY\DataGridBundle\Grid\Export\Export;
use APY\DataGridBundle\Grid\Export\ExportInterface;
+use APY\DataGridBundle\Grid\Source\Entity;
+use APY\DataGridBundle\Grid\Source\Source;
+use Symfony\Component\DependencyInjection\Container;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Twig\TemplateWrapper;
+use Twig\Environment ;
+use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
-class Grid
+class Grid implements GridInterface
{
- const REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED = '__action_all_keys';
- const REQUEST_QUERY_MASS_ACTION = '__action_id';
- const REQUEST_QUERY_EXPORT = '__export_id';
- const REQUEST_QUERY_TWEAK = '__tweak_id';
- const REQUEST_QUERY_PAGE = '_page';
- const REQUEST_QUERY_LIMIT = '_limit';
- const REQUEST_QUERY_ORDER = '_order';
- const REQUEST_QUERY_TEMPLATE = '_template';
- const REQUEST_QUERY_RESET = '_reset';
-
- /**
- * @var \Symfony\Component\DependencyInjection\Container
+ public const REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED = '__action_all_keys';
+ public const REQUEST_QUERY_MASS_ACTION = '__action_id';
+ public const REQUEST_QUERY_EXPORT = '__export_id';
+ public const REQUEST_QUERY_TWEAK = '__tweak_id';
+ public const REQUEST_QUERY_PAGE = '_page';
+ public const REQUEST_QUERY_LIMIT = '_limit';
+ public const REQUEST_QUERY_ORDER = '_order';
+ public const REQUEST_QUERY_TEMPLATE = '_template';
+ public const REQUEST_QUERY_RESET = '_reset';
+
+ public const SOURCE_ALREADY_SETTED_EX_MSG = 'The source of the grid is already set.';
+ public const SOURCE_NOT_SETTED_EX_MSG = 'The source of the grid must be set.';
+ public const TWEAK_MALFORMED_ID_EX_MSG = 'Tweak id "%s" is malformed. The id have to match this regex ^[0-9a-zA-Z_\+-]+';
+ public const TWIG_TEMPLATE_LOAD_EX_MSG = 'Unable to load template';
+ public const NOT_VALID_LIMIT_EX_MSG = 'Limit has to be array or integer';
+ public const NOT_VALID_PAGE_NUMBER_EX_MSG = 'Page must be a positive number';
+ public const NOT_VALID_MAX_RESULT_EX_MSG = 'Max results must be a positive number.';
+ public const MASS_ACTION_NOT_DEFINED_EX_MSG = 'Action %s is not defined.';
+ public const MASS_ACTION_CALLBACK_NOT_VALID_EX_MSG = 'Callback %s is not callable or Controller action';
+ public const EXPORT_NOT_DEFINED_EX_MSG = 'Export %s is not defined.';
+ public const PAGE_NOT_VALID_EX_MSG = 'Page must be a positive number';
+ public const COLUMN_ORDER_NOT_VALID_EX_MSG = '%s is not a valid order.';
+ public const DEFAULT_LIMIT_NOT_VALID_EX_MSG = 'Limit must be a positive number';
+ public const LIMIT_NOT_DEFINED_EX_MSG = 'Limit %s is not defined in limits.';
+ public const NO_ROWS_RETURNED_EX_MSG = 'Source have to return Rows object.';
+ public const INVALID_TOTAL_COUNT_EX_MSG = 'Source function getTotalCount need to return integer result, returned: %s';
+ public const NOT_VALID_TWEAK_ID_EX_MSG = 'Tweak with id "%s" doesn\'t exists';
+ public const GET_FILTERS_NO_REQUEST_HANDLED_EX_MSG = 'getFilters method is only available in the manipulate callback function or after the call of the method isRedirected of the grid.';
+ public const HAS_FILTER_NO_REQUEST_HANDLED_EX_MSG = 'hasFilters method is only available in the manipulate callback function or after the call of the method isRedirected of the grid.';
+ public const TWEAK_NOT_DEFINED_EX_MSG = 'Tweak %s is not defined.';
+
+ /**
+ * @var Container
*/
protected $container;
@@ -53,14 +80,13 @@ class Grid
protected $session;
/**
- * @var \Symfony\Component\HttpFoundation\Request
+ * @var Request
*/
protected $request;
- /**
- * @var \Symfony\Component\Security\Core\SecurityContext
- */
- protected $securityContext;
+ protected AuthorizationCheckerInterface $securityContext;
+
+ protected Environment $twig;
/**
* @var string
@@ -82,15 +108,12 @@ class Grid
*/
protected $routeParameters;
- /**
- * @var \APY\DataGridBundle\Grid\Source\Source
- */
- protected $source;
+ protected ?Source $source = null;
/**
- * @var boolean
+ * @var bool
*/
- protected $prepared = false;
+ protected $prepared = false;
/**
* @var int
@@ -110,35 +133,35 @@ class Grid
/**
* @var array
*/
- protected $limits = array();
+ protected $limits = [];
/**
- * @var \APY\DataGridBundle\Grid\Columns|\APY\DataGridBundle\Grid\Column\Column[]
+ * @var Columns|Column[]
*/
protected $columns;
/**
- * @var \APY\DataGridBundle\Grid\Rows
+ * @var Rows
*/
protected $rows;
/**
- * @var \APY\DataGridBundle\Grid\Action\MassAction[]
+ * @var Action\MassAction[]
*/
- protected $massActions = array();
+ protected $massActions = [];
/**
- * @var \APY\DataGridBundle\Grid\Action\RowAction[]
+ * @var Action\RowAction[]
*/
- protected $rowActions = array();
+ protected $rowActions = [];
/**
- * @var boolean
+ * @var bool
*/
protected $showFilters = true;
/**
- * @var boolean
+ * @var bool
*/
protected $showTitles = true;
@@ -150,7 +173,7 @@ class Grid
/**
* @var array|object session
*/
- protected $sessionData;
+ protected $sessionData = [];
/**
* @var string
@@ -158,12 +181,12 @@ class Grid
protected $prefixTitle = '';
/**
- * @var boolean
+ * @var bool
*/
protected $persistence = false;
/**
- * @var boolean
+ * @var bool
*/
protected $newSession = false;
@@ -178,17 +201,17 @@ class Grid
protected $noResultMessage;
/**
- * @var \APY\DataGridBundle\Grid\Export\Export[]
+ * @var Export[]
*/
- protected $exports = array();
+ protected $exports = [];
/**
- * @var boolean
+ * @var bool
*/
protected $redirect = null;
/**
- * @var boolean
+ * @var bool
*/
protected $isReadyForExport = false;
@@ -210,95 +233,111 @@ class Grid
/**
* @var array
*/
- protected $items = array();
+ protected $items = [];
/**
- * Data junction of the grid
+ * Data junction of the grid.
*
* @var int
*/
protected $dataJunction = Column::DATA_CONJUNCTION;
/**
- * Permanent filters
+ * Permanent filters.
*
* @var array
*/
- protected $permanentFilters = array();
+ protected $permanentFilters = [];
/**
- * Default filters
+ * Default filters.
*
* @var array
*/
- protected $defaultFilters = array();
+ protected $defaultFilters = [];
/**
- * Default order (e.g. my_column_id|asc)
+ * Default order (e.g. my_column_id|asc).
*
* @var string
*/
protected $defaultOrder;
/**
- * Default limit
+ * Default limit.
*
- * @var integer
+ * @var int
*/
protected $defaultLimit;
/**
- * Default page
+ * Default page.
*
* @var int
*/
protected $defaultPage;
/**
- * Tweaks
+ * Tweaks.
*
* @var array
*/
- protected $tweaks = array();
+ protected $tweaks = [];
/**
- * Default Tweak
+ * Default Tweak.
*
* @var string
*/
protected $defaultTweak;
/**
- * Filters in session
+ * Filters in session.
+ *
* @var array
*/
protected $sessionFilters;
// Lazy parameters
- protected $lazyAddColumn = array();
- protected $lazyHiddenColumns = array();
- protected $lazyVisibleColumns = array();
- protected $lazyHideShowColumns = array();
+ protected $lazyAddColumn = [];
+ protected $lazyHiddenColumns = [];
+ protected $lazyVisibleColumns = [];
+ protected $lazyHideShowColumns = [];
// Lazy parameters for the action column
protected $actionsColumnSize;
protected $actionsColumnTitle;
/**
- * @param \Symfony\Component\DependencyInjection\Container $container
- * @param string $id set if you are using more then one grid inside controller
+ * The grid configuration.
+ */
+ private ?\APY\DataGridBundle\Grid\GridConfigInterface $config;
+
+ /**
+ * Constructor.
+ *
+ * @param Container $container
+ * @param string $id set if you are using more then one grid inside controller
+ * @param GridConfigInterface|null $config The grid configuration.
*/
- public function __construct($container, $id = '')
+ public function __construct($container, AuthorizationCheckerInterface $securityContext, Environment $twig, $id = '', GridConfigInterface $config = null)
{
+ // @todo: why the whole container is injected?
$this->container = $container;
+ $this->config = $config;
$this->router = $container->get('router');
- $this->request = $container->get('request');
+ $this->request = $container->get('request_stack')->getCurrentRequest();
$this->session = $this->request->getSession();
- $this->securityContext = $container->get('security.context');
-
+ $this->securityContext = $securityContext;
+ $this->twig = $twig;
$this->id = $id;
+ // even id is set, do create hash early
+ if (!empty($this->id)) {
+ $this->createHash();
+ }
+
$this->columns = new Columns($this->securityContext);
$this->routeParameters = $this->request->attributes->all();
@@ -310,18 +349,141 @@ public function __construct($container, $id = '')
}
/**
- * Sets Source to the Grid
+ * {@inheritdoc}
+ */
+ public function initialize()
+ {
+ if (!$this->config) {
+ return $this;
+ }
+
+ $config = $this->config;
+
+ $this->setPersistence($config->isPersisted());
+
+ // Route parameters
+ $routeParameters = [];
+ $parameters = $config->getRouteParameters();
+ if (!empty($parameters)) {
+ $routeParameters = $parameters;
+ foreach ($routeParameters as $parameter => $value) {
+ $this->setRouteParameter($parameter, $value);
+ }
+ }
+
+ // Route
+ if (null !== $config->getRoute()) {
+ $this->setRouteUrl($this->router->generate($config->getRoute(), $routeParameters));
+ }
+
+ // Route
+ if (null !== $config->getRoute()) {
+ $this->setRouteUrl($this->router->generate($config->getRoute(), $routeParameters));
+ }
+
+ // Columns
+ foreach ($this->lazyAddColumn as $columnInfo) {
+ /** @var Column $column */
+ $column = $columnInfo['column'];
+
+ if (!$config->isFilterable()) {
+ $column->setFilterable(false);
+ }
+
+ if (!$config->isSortable()) {
+ $column->setSortable(false);
+ }
+ }
+
+ // Source
+ $source = $config->getSource();
+
+ if (null !== $source) {
+ $this->source = $source;
+
+ $source->initialise($this->container);
+
+ if ($source instanceof Entity) {
+ $groupBy = $config->getGroupBy();
+ if (null !== $groupBy) {
+ if (!is_array($groupBy)) {
+ $groupBy = [$groupBy];
+ }
+
+ // Must be set after source because initialize method reset groupBy property
+ $source->setGroupBy($groupBy);
+ }
+ }
+ }
+
+ // Order
+ if (null !== $config->getSortBy()) {
+ $this->setDefaultOrder($config->getSortBy(), $config->getOrder());
+ }
+
+ if (null !== $config->getMaxPerPage()) {
+ $this->setLimits($config->getMaxPerPage());
+ }
+
+ $this
+ ->setMaxResults($config->getMaxResults())
+ ->setPage($config->getPage());
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function handleRequest(Request $request)
+ {
+ if (null === $this->source) {
+ throw new \LogicException(self::SOURCE_NOT_SETTED_EX_MSG);
+ }
+
+ $this->request = $request;
+ $this->session = $request->getSession();
+
+ $this->createHash();
+
+ $this->requestData = $request->get($this->hash);
+
+ $this->processPersistence();
+
+ $this->sessionData = (array) $this->session->get($this->hash);
+
+ $this->processLazyParameters();
+
+ if (!empty($this->requestData)) {
+ $this->processRequestData();
+ }
+
+ if ($this->newSession) {
+ $this->setDefaultSessionData();
+ }
+
+ $this->processPermanentFilters();
+
+ $this->processSessionData();
+
+ $this->prepare();
+
+ return $this;
+ }
+
+ /**
+ * Sets Source to the Grid.
*
* @param $source
*
- * @return self
- *
* @throws \InvalidArgumentException
+ *
+ * @return self
*/
public function setSource(Source $source)
{
if ($this->source !== null) {
- throw new \InvalidArgumentException('The source of the grid is already set.');
+ throw new \InvalidArgumentException(self::SOURCE_ALREADY_SETTED_EX_MSG);
}
$this->source = $source;
@@ -334,7 +496,7 @@ public function setSource(Source $source)
return $this;
}
- public function getSource()
+ public function getSource(): ?Source
{
return $this->source;
}
@@ -345,7 +507,7 @@ public function getSource()
public function isReadyForRedirect()
{
if ($this->source === null) {
- throw new \Exception('The source of the grid is not set.');
+ throw new \Exception(self::SOURCE_NOT_SETTED_EX_MSG);
}
if ($this->redirect !== null) {
@@ -389,16 +551,16 @@ public function isReadyForRedirect()
protected function getCurrentUri()
{
- return $this->request->getScheme().'://'.$this->request->getHttpHost().$this->request->getBaseUrl().$this->request->getPathInfo();
+ return $this->request->getScheme() . '://' . $this->request->getHttpHost() . $this->request->getBaseUrl() . $this->request->getPathInfo();
}
protected function processPersistence()
{
- $referer = strtok($this->request->headers->get('referer'), '?');
+ $referer = strtok((string) $this->request->headers->get('referer'), '?');
// Persistence or reset - kill previous session
if ((!$this->request->isXmlHttpRequest() && !$this->persistence && $referer != $this->getCurrentUri())
- || isset($this->requestData[self::REQUEST_QUERY_RESET])) {
+ || isset($this->requestData[self::REQUEST_QUERY_RESET])) {
$this->session->remove($this->hash);
}
@@ -421,7 +583,7 @@ protected function processLazyParameters()
// Visible columns
if (!empty($this->lazyVisibleColumns)) {
- $columnNames = array();
+ $columnNames = [];
foreach ($this->columns as $column) {
$columnNames[] = $column->getId();
}
@@ -444,7 +606,7 @@ protected function processRequestData()
{
$this->processMassActions($this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION));
- if ($this->processExports($this->getFromRequest(Grid::REQUEST_QUERY_EXPORT))
+ if ($this->processExports($this->getFromRequest(self::REQUEST_QUERY_EXPORT))
|| $this->processTweaks($this->getFromRequest(self::REQUEST_QUERY_TWEAK))) {
return;
}
@@ -461,7 +623,7 @@ protected function processRequestData()
}
/**
- * Process mass actions
+ * Process mass actions.
*
* @param int $actionId
*
@@ -473,48 +635,55 @@ protected function processMassActions($actionId)
if ($actionId > -1 && '' !== $actionId) {
if (array_key_exists($actionId, $this->massActions)) {
$action = $this->massActions[$actionId];
- $actionAllKeys = (boolean)$this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED);
- $actionKeys = $actionAllKeys == false ? (array) $this->getFromRequest(MassActionColumn::ID) : array();
+ $actionAllKeys = (bool) $this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED);
+ $actionKeys = $actionAllKeys === false ? array_keys((array) $this->getFromRequest(MassActionColumn::ID)) : [];
$this->processSessionData();
if ($actionAllKeys) {
$this->page = 0;
$this->limit = 0;
}
+
$this->prepare();
+ if ($actionAllKeys === true) {
+ foreach ($this->rows as $row) {
+ $actionKeys[] = $row->getPrimaryFieldValue();
+ }
+ }
+
if (is_callable($action->getCallback())) {
- $this->massActionResponse = call_user_func($action->getCallback(), array_keys($actionKeys), $actionAllKeys, $this->session, $action->getParameters());
+ $this->massActionResponse = call_user_func($action->getCallback(), $actionKeys, $actionAllKeys, $this->session, $action->getParameters());
} elseif (strpos($action->getCallback(), ':') !== false) {
$path = array_merge(
- array(
- 'primaryKeys' => array_keys($actionKeys),
+ [
+ 'primaryKeys' => $actionKeys,
'allPrimaryKeys' => $actionAllKeys,
- '_controller' => $action->getCallback()
- ),
+ '_controller' => $action->getCallback(),
+ ],
$action->getParameters()
);
- $subRequest = $this->container->get('request')->duplicate(array(), null, $path);
+ $subRequest = $this->request->duplicate([], null, $path);
$this->massActionResponse = $this->container->get('http_kernel')->handle($subRequest, \Symfony\Component\HttpKernel\HttpKernelInterface::SUB_REQUEST);
} else {
- throw new \RuntimeException(sprintf('Callback %s is not callable or Controller action', $action->getCallback()));
+ throw new \RuntimeException(sprintf(self::MASS_ACTION_CALLBACK_NOT_VALID_EX_MSG, $action->getCallback()));
}
} else {
- throw new \OutOfBoundsException(sprintf('Action %s is not defined.', $actionId));
+ throw new \OutOfBoundsException(sprintf(self::MASS_ACTION_NOT_DEFINED_EX_MSG, $actionId));
}
}
}
/**
- * Process exports
+ * Process exports.
*
* @param int $exportId
*
- * @return boolean
- *
* @throws \OutOfBoundsException
+ *
+ * @return bool
*/
protected function processExports($exportId)
{
@@ -530,6 +699,7 @@ protected function processExports($exportId)
$export = $this->exports[$exportId];
if ($export instanceof ContainerAwareInterface) {
$export->setContainer($this->container);
+ $export->setTwig($this->twig);
}
$export->computeData($this);
@@ -537,7 +707,7 @@ protected function processExports($exportId)
return true;
} else {
- throw new \OutOfBoundsException(sprintf('Export %s is not defined.', $exportId));
+ throw new \OutOfBoundsException(sprintf(self::EXPORT_NOT_DEFINED_EX_MSG, $exportId));
}
}
@@ -545,28 +715,28 @@ protected function processExports($exportId)
}
/**
- * Process tweaks
+ * Process tweaks.
*
* @param int $tweakId
*
- * @return boolean
- *
* @throws \OutOfBoundsException
+ *
+ * @return bool
*/
protected function processTweaks($tweakId)
{
- if ($tweakId != null) {
+ if ($tweakId !== null) {
if (array_key_exists($tweakId, $this->tweaks)) {
$tweak = $this->tweaks[$tweakId];
$saveAsActive = false;
if (isset($tweak['reset'])) {
- $this->sessionData = array();
+ $this->sessionData = [];
$this->session->remove($this->hash);
}
if (isset($tweak['filters'])) {
- $this->defaultFilters = array();
+ $this->defaultFilters = [];
$this->setDefaultFilters($tweak['filters']);
$this->processDefaultFilters();
$saveAsActive = true;
@@ -643,7 +813,7 @@ protected function processTweaks($tweakId)
return true;
} else {
- throw new \OutOfBoundsException(sprintf('Tweak %s is not defined.', $tweakId));
+ throw new \OutOfBoundsException(sprintf(self::TWEAK_NOT_DEFINED_EX_MSG, $tweakId));
}
}
@@ -660,6 +830,17 @@ protected function processRequestFilters()
// Get data from request
$data = $this->getFromRequest($ColumnId);
+ //if no item is selectd in multi select filter : simulate empty first choice
+ if ($column->getFilterType() == 'select'
+ && $column->getSelectMulti() === true
+ && $data === null
+ && $this->getFromRequest(self::REQUEST_QUERY_PAGE) === null
+ && $this->getFromRequest(self::REQUEST_QUERY_ORDER) === null
+ && $this->getFromRequest(self::REQUEST_QUERY_LIMIT) === null
+ && ($this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION) === null || $this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION) == '-1')) {
+ $data = ['from' => ''];
+ }
+
// Store in the session
$this->set($ColumnId, $data);
@@ -677,9 +858,9 @@ protected function processPage($page, $filtering = false)
{
// Set to the first page if this is a request of order, limit, mass action or filtering
if ($this->getFromRequest(self::REQUEST_QUERY_ORDER) !== null
- || $this->getFromRequest(self::REQUEST_QUERY_LIMIT) !== null
- || $this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION) !== null
- || $filtering) {
+ || $this->getFromRequest(self::REQUEST_QUERY_LIMIT) !== null
+ || $this->getFromRequest(self::REQUEST_QUERY_MASS_ACTION) !== null
+ || $filtering) {
$this->set(self::REQUEST_QUERY_PAGE, 0);
} else {
$this->set(self::REQUEST_QUERY_PAGE, $page);
@@ -692,7 +873,7 @@ protected function processOrder($order)
list($columnId, $columnOrder) = explode('|', $order);
$column = $this->columns->getColumnById($columnId);
- if ($column->isSortable() && in_array(strtolower($columnOrder), array('asc', 'desc'))) {
+ if ($column->isSortable() && in_array(strtolower($columnOrder), ['asc', 'desc'])) {
$this->set(self::REQUEST_QUERY_ORDER, $order);
}
}
@@ -715,7 +896,7 @@ protected function setDefaultSessionData()
if ((int) $this->defaultPage >= 0) {
$this->set(self::REQUEST_QUERY_PAGE, $this->defaultPage);
} else {
- throw new \InvalidArgumentException('Page must be a positive number');
+ throw new \InvalidArgumentException(self::NOT_VALID_PAGE_NUMBER_EX_MSG);
}
}
@@ -724,10 +905,10 @@ protected function setDefaultSessionData()
list($columnId, $columnOrder) = explode('|', $this->defaultOrder);
$this->columns->getColumnById($columnId);
- if (in_array(strtolower($columnOrder), array('asc', 'desc'))) {
+ if (in_array(strtolower($columnOrder), ['asc', 'desc'])) {
$this->set(self::REQUEST_QUERY_ORDER, $this->defaultOrder);
} else {
- throw new \InvalidArgumentException($columnOrder . ' is not a valid order.');
+ throw new \InvalidArgumentException(sprintf(self::COLUMN_ORDER_NOT_VALID_EX_MSG, $columnOrder));
}
}
@@ -736,10 +917,10 @@ protected function setDefaultSessionData()
if (isset($this->limits[$this->defaultLimit])) {
$this->set(self::REQUEST_QUERY_LIMIT, $this->defaultLimit);
} else {
- throw new \InvalidArgumentException(sprintf('Limit %s is not defined in limits.', $this->defaultLimit));
+ throw new \InvalidArgumentException(sprintf(self::LIMIT_NOT_DEFINED_EX_MSG, $this->defaultLimit));
}
} else {
- throw new \InvalidArgumentException('Limit must be a positive number');
+ throw new \InvalidArgumentException(self::DEFAULT_LIMIT_NOT_VALID_EX_MSG);
}
}
@@ -750,8 +931,8 @@ protected function setDefaultSessionData()
$this->saveSession();
}
- /**
- * Store permanent filters to the session and disable the filter capability for the column if there are permanent filters
+ /**
+ * Store permanent filters to the session and disable the filter capability for the column if there are permanent filters.
*/
protected function processFilters($permanent = true)
{
@@ -766,7 +947,7 @@ protected function processFilters($permanent = true)
// Convert simple value
if (!is_array($value) || !is_string(key($value))) {
- $value = array('from' => $value);
+ $value = ['from' => $value];
}
// Convert boolean value
@@ -777,11 +958,11 @@ protected function processFilters($permanent = true)
// Convert simple value with select filter
if ($column->getFilterType() === 'select') {
if (isset($value['from']) && !is_array($value['from'])) {
- $value['from'] = array($value['from']);
+ $value['from'] = [$value['from']];
}
if (isset($value['to']) && !is_array($value['to'])) {
- $value['to'] = array($value['to']);
+ $value['to'] = [$value['to']];
}
}
@@ -836,11 +1017,11 @@ protected function processSessionData()
}
/**
- * Prepare Grid for Drawing
- *
- * @return self
+ * Prepare Grid for Drawing.
*
* @throws \Exception
+ *
+ * @return self
*/
protected function prepare()
{
@@ -855,7 +1036,7 @@ protected function prepare()
}
if (!$this->rows instanceof Rows) {
- throw new \Exception('Source have to return Rows object.');
+ throw new \Exception(self::NO_ROWS_RETURNED_EX_MSG);
}
if (count($this->rows) == 0 && $this->page > 0) {
@@ -892,22 +1073,6 @@ protected function prepare()
$row->setPrimaryField($primaryColumnId);
}
- //@todo refactor autohide titles when no title is set
- if (!$this->showTitles) {
- $this->showTitles = false;
- foreach ($this->columns as $column) {
- if (!$this->showTitles) {
- break;
- }
-
- if ($column->getTitle() != '') {
- $this->showTitles = true;
-
- break;
- }
- }
- }
-
//get size
if ($this->source->isDataLoaded()) {
$this->source->populateSelectFiltersFromData($this->columns);
@@ -918,7 +1083,7 @@ protected function prepare()
}
if (!is_int($this->totalCount)) {
- throw new \Exception(sprintf('Source function getTotalCount need to return integer result, returned: %s', gettype($this->totalCount)));
+ throw new \Exception(sprintf(self::INVALID_TOTAL_COUNT_EX_MSG, gettype($this->totalCount)));
}
$this->prepared = true;
@@ -938,6 +1103,7 @@ protected function getFromRequest($key)
if (isset($this->requestData[$key])) {
return $this->requestData[$key];
}
+ return null;
}
/**
@@ -952,18 +1118,21 @@ protected function get($key)
if (isset($this->sessionData[$key])) {
return $this->sessionData[$key];
}
+ return null;
}
/**
* Writes data to the session.
*
- * @param string $key A unique key identifying the data
- * @param mixed $data Data associated with the key
+ * @param string $key A unique key identifying the data
+ * @param mixed $data Data associated with the key
*/
protected function set($key, $data)
{
// Only the filters values are removed from the session
- if (isset($data['from']) && ((is_string($data['from']) && $data['from'] === '') || (is_array($data['from']) && $data['from'][0] === ''))) {
+ $fromIsEmpty = isset($data['from']) && ((is_string($data['from']) && $data['from'] === '') || (is_array($data['from']) && $data['from'][0] === ''));
+ $toIsSet = isset($data['to']) && (is_string($data['to']) && $data['to'] !== '');
+ if ($fromIsEmpty && !$toIsSet) {
if (array_key_exists($key, $this->sessionData)) {
unset($this->sessionData[$key]);
}
@@ -974,14 +1143,14 @@ protected function set($key, $data)
protected function saveSession()
{
- if (!empty($this->sessionData)) {
+ if (!empty($this->sessionData) && !empty($this->hash)) {
$this->session->set($this->hash, $this->sessionData);
}
}
protected function createHash()
{
- $this->hash = 'grid_'. (empty($this->id) ? md5($this->request->get('_controller').$this->columns->getHash().$this->source->getHash()) : $this->getId());
+ $this->hash = 'grid_' . (empty($this->id) ? md5($this->request->get('_controller') . $this->columns->getHash() . $this->source->getHash()) : $this->getId());
}
public function getHash()
@@ -990,7 +1159,7 @@ public function getHash()
}
/**
- * Adds custom column to the grid
+ * Adds custom column to the grid.
*
* @param $column
* @param int $position
@@ -999,13 +1168,13 @@ public function getHash()
*/
public function addColumn($column, $position = 0)
{
- $this->lazyAddColumn[] = array('column' => $column, 'position' => $position);
+ $this->lazyAddColumn[] = ['column' => $column, 'position' => $position];
return $this;
}
/**
- * Get a column by its identifier
+ * Get a column by its identifier.
*
* @param $columnId
*
@@ -1023,9 +1192,9 @@ public function getColumn($columnId)
}
/**
- * Returns Grid Columns
+ * Returns Grid Columns.
*
- * @return Column\Column[]|Columns
+ * @return Column[]|Columns
*/
public function getColumns()
{
@@ -1033,10 +1202,11 @@ public function getColumns()
}
/**
- * Returns true if column exists in columns and lazyAddColumn properties
+ * Returns true if column exists in columns and lazyAddColumn properties.
*
* @param $columnId
- * @return boolean
+ *
+ * @return bool
*/
public function hasColumn($columnId)
{
@@ -1050,7 +1220,7 @@ public function hasColumn($columnId)
}
/**
- * Sets Array of Columns to the grid
+ * Sets Array of Columns to the grid.
*
* @param $columns
*
@@ -1066,10 +1236,10 @@ public function setColumns(Columns $columns)
/**
* Sets order of Columns passing an array of column ids
* If the list of ids is uncomplete, the remaining columns will be
- * placed after
+ * placed after.
*
* @param array $columnIds
- * @param boolean $keepOtherColumns
+ * @param bool $keepOtherColumns
*
* @return self
*/
@@ -1081,7 +1251,7 @@ public function setColumnsOrder(array $columnIds, $keepOtherColumns = true)
}
/**
- * Adds Mass Action
+ * Adds Mass Action.
*
* @param Action\MassActionInterface $action
*
@@ -1097,7 +1267,7 @@ public function addMassAction(MassActionInterface $action)
}
/**
- * Returns Mass Actions
+ * Returns Mass Actions.
*
* @return Action\MassAction[]
*/
@@ -1107,21 +1277,22 @@ public function getMassActions()
}
/**
- * Add a tweak
- * @param string title title of the tweak
- * @param array $tweak array('filters' => array, 'order' => 'colomunId|order', 'page' => integer, 'limit' => integer, 'export' => integer, 'massAction' => integer)
- * @param string id id of the tweak matching the regex ^[0-9a-zA-Z_\+-]+
- * @param string group group of the tweak
+ * Add a tweak.
+ *
+ * @param string $title title of the tweak
+ * @param array $tweak array('filters' => array, 'order' => 'colomunId|order', 'page' => integer, 'limit' => integer, 'export' => integer, 'massAction' => integer)
+ * @param string $id id of the tweak matching the regex ^[0-9a-zA-Z_\+-]+
+ * @param string $group group of the tweak
*
* @return self
*/
public function addTweak($title, array $tweak, $id = null, $group = null)
{
if ($id !== null && !preg_match('/^[0-9a-zA-Z_\+-]+$/', $id)) {
- throw new \InvalidArgumentException(sprintf('Tweak id "%s" is malformed. The id have to match this regex ^[0-9a-zA-Z_\+-]+', $id));
+ throw new \InvalidArgumentException(sprintf(self::TWEAK_MALFORMED_ID_EX_MSG, $id));
}
- $tweak = array_merge(array('id' => $id, 'title' => $title, 'group' => $group), $tweak);
+ $tweak = array_merge(['id' => $id, 'title' => $title, 'group' => $group], $tweak);
if (isset($id)) {
$this->tweaks[$id] = $tweak;
} else {
@@ -1133,28 +1304,34 @@ public function addTweak($title, array $tweak, $id = null, $group = null)
/**
* Returns tweaks
- * Add the url of the tweak
+ * Add the url of the tweak.
*
* @return array
*/
public function getTweaks()
{
- $separator = strpos($this->getRouteUrl(), '?') ? '&' : '?';
- $url = $this->getRouteUrl().$separator.$this->getHash().'['.Grid::REQUEST_QUERY_TWEAK.']=';
+ $separator = strpos($this->getRouteUrl(), '?') ? '&' : '?';
+ $url = $this->getRouteUrl() . $separator . $this->getHash() . '[' . self::REQUEST_QUERY_TWEAK . ']=';
foreach ($this->tweaks as $id => $tweak) {
- $this->tweaks[$id] = array_merge($tweak, array('url' => $url.$id));
+ $this->tweaks[$id] = array_merge($tweak, ['url' => $url . $id]);
}
return $this->tweaks;
}
+ public function getRawTweaks()
+ {
+ return $this->tweaks;
+ }
+
public function getActiveTweaks()
{
return (array) $this->get('tweaks');
}
+
/**
- * Returns a tweak
+ * Returns a tweak.
*
* @return array
*/
@@ -1165,11 +1342,11 @@ public function getTweak($id)
return $tweaks[$id];
}
- throw new \InvalidArgumentException(sprintf('Tweak with id "%s" doesn\'t exists', $id));
+ throw new \InvalidArgumentException(sprintf(self::NOT_VALID_TWEAK_ID_EX_MSG, $id));
}
/**
- * Returns tweaks with a specific group
+ * Returns tweaks with a specific group.
*
* @return array
*/
@@ -1189,10 +1366,12 @@ public function getTweaksGroup($group)
public function getActiveTweakGroup($group)
{
$tweaks = $this->getActiveTweaks();
+
return isset($tweaks[$group]) ? $tweaks[$group] : -1;
}
+
/**
- * Adds Row Action
+ * Adds Row Action.
*
* @param Action\RowActionInterface $action
*
@@ -1208,7 +1387,7 @@ public function addRowAction(RowActionInterface $action)
}
/**
- * Returns Row Actions
+ * Returns Row Actions.
*
* @return Action\RowAction[]
*/
@@ -1218,23 +1397,22 @@ public function getRowActions()
}
/**
- * Sets template for export
- *
- * @param Export $template
+ * Sets template for export.
*
- * @return self
+ * @param TemplateWrapper|string $template
*
* @throws \Exception
+ *
+ * @return self
*/
public function setTemplate($template)
{
if ($template !== null) {
- if ($template instanceof \Twig_Template) {
+ if ($template instanceof TemplateWrapper) {
$template = '__SELF__' . $template->getTemplateName();
- } elseif (!is_string($template) && $template === null) {
- throw new \Exception('Unable to load template');
+ } elseif (!is_string($template)) {
+ throw new \Exception(self::TWIG_TEMPLATE_LOAD_EX_MSG);
}
-
$this->set(self::REQUEST_QUERY_TEMPLATE, $template);
$this->saveSession();
}
@@ -1243,9 +1421,9 @@ public function setTemplate($template)
}
/**
- * Returns template
+ * Returns template.
*
- * @return Twig_Template
+ * @return string
*/
public function getTemplate()
{
@@ -1253,7 +1431,7 @@ public function getTemplate()
}
/**
- * Adds Export
+ * Adds Export.
*
* @param ExportInterface $export
*
@@ -1269,9 +1447,9 @@ public function addExport(ExportInterface $export)
}
/**
- * Returns exports
+ * Returns exports.
*
- * @return Export[]
+ * @return ExportInterface[]
*/
public function getExports()
{
@@ -1279,30 +1457,30 @@ public function getExports()
}
/**
- * Returns the export response
+ * Returns the export response.
*
- * @return Export[]
+ * @return Response
*/
- public function getExportResponse()
+ public function getExportResponse(): Response
{
return $this->exportResponse;
}
/**
- * Returns the mass action response
+ * Returns the mass action response.
*
- * @return Export[]
+ * @return Response
*/
- public function getMassActionResponse()
+ public function getMassActionResponse(): Response
{
return $this->massActionResponse;
}
/**
- * Sets Route Parameters
+ * Sets Route Parameters.
*
* @param string $parameter
- * @param mixed $value
+ * @param mixed $value
*
* @return self
*/
@@ -1314,7 +1492,7 @@ public function setRouteParameter($parameter, $value)
}
/**
- * Returns Route Parameters
+ * Returns Route Parameters.
*
* @return array
*/
@@ -1324,9 +1502,9 @@ public function getRouteParameters()
}
/**
- * Sets Route URL
+ * Sets Route URL.
*
- * @param string routeUrl
+ * @param string $routeUrl
*
* @return self
*/
@@ -1338,14 +1516,14 @@ public function setRouteUrl($routeUrl)
}
/**
- * Returns Route URL
+ * Returns Route URL.
*
* @return string
*/
public function getRouteUrl()
{
if ($this->routeUrl === null) {
- $this->routeUrl = $this->router->generate($this->request->get('_route'), $this->getRouteParameters());
+ $this->routeUrl = $this->router->generate((string) $this->request->get('_route'), $this->getRouteParameters());
}
return $this->routeUrl;
@@ -1362,10 +1540,10 @@ public function isMassActionRedirect()
}
/**
- * Set value for filters
+ * Set value for filters.
*
- * @param array Hash of columnName => initValue
- * @param boolean permanent filters ?
+ * @param array $filters Hash of columnName => initValue
+ * @param bool $permanent filters ?
*
* @return self
*/
@@ -1383,10 +1561,9 @@ protected function setFilters(array $filters, $permanent = true)
}
/**
- * Set permanent value for filters
+ * Set permanent value for filters.
*
- * @param array Hash of columnName => initValue
- * @param boolean fixed filters ?
+ * @param array $filters Hash of columnName => initValue
*
* @return self
*/
@@ -1396,9 +1573,9 @@ public function setPermanentFilters(array $filters)
}
/**
- * Set default value for filters
+ * Set default value for filters.
*
- * @param array Hash of columnName => initValue
+ * @param array $filters Hash of columnName => initValue
*
* @return self
*/
@@ -1410,7 +1587,7 @@ public function setDefaultFilters(array $filters)
/**
* Set the default grid order.
*
- * @param array Hash of columnName => initValue
+ * @param $columnId
*
* @return self
*/
@@ -1423,7 +1600,7 @@ public function setDefaultOrder($columnId, $order)
}
/**
- * Sets unique filter identification
+ * Sets unique filter identification.
*
* @param $id
*
@@ -1437,7 +1614,7 @@ public function setId($id)
}
/**
- * Returns unique filter identifier
+ * Returns unique filter identifier.
*
* @return string
*/
@@ -1446,9 +1623,8 @@ public function getId()
return $this->id;
}
-
/**
- * Sets persistence
+ * Sets persistence.
*
* @param $persistence
*
@@ -1462,9 +1638,9 @@ public function setPersistence($persistence)
}
/**
- * Returns persistence
+ * Returns persistence.
*
- * @return boolean
+ * @return bool
*/
public function getPersistence()
{
@@ -1484,33 +1660,33 @@ public function setDataJunction($dataJunction)
}
/**
- * Sets Limits
+ * Sets Limits.
*
* @param mixed $limits e.g. 10, array(10, 1000) or array(10 => '10', 1000 => '1000')
*
- * @return self
- *
* @throws \InvalidArgumentException
+ *
+ * @return self
*/
public function setLimits($limits)
{
if (is_array($limits)) {
- if ((int)key($limits) === 0) {
+ if ((int) key($limits) === 0) {
$this->limits = array_combine($limits, $limits);
} else {
$this->limits = $limits;
}
} elseif (is_int($limits)) {
- $this->limits = array($limits => (string)$limits);
+ $this->limits = [$limits => (string) $limits];
} else {
- throw new \InvalidArgumentException('Limit has to be array or integer');
+ throw new \InvalidArgumentException(self::NOT_VALID_LIMIT_EX_MSG);
}
return $this;
}
/**
- * Returns limits
+ * Returns limits.
*
* @return array
*/
@@ -1520,7 +1696,7 @@ public function getLimits()
}
/**
- * Returns selected Limit (Rows Per Page)
+ * Returns selected Limit (Rows Per Page).
*
* @return mixed
*/
@@ -1530,7 +1706,7 @@ public function getLimit()
}
/**
- * Sets default Limit
+ * Sets default Limit.
*
* @param $limit
*
@@ -1544,7 +1720,7 @@ public function setDefaultLimit($limit)
}
/**
- * Sets default Page
+ * Sets default Page.
*
* @param $page
*
@@ -1558,7 +1734,7 @@ public function setDefaultPage($page)
}
/**
- * Sets default Tweak
+ * Sets default Tweak.
*
* @param $tweakId
*
@@ -1572,27 +1748,27 @@ public function setDefaultTweak($tweakId)
}
/**
- * Sets current Page (internal)
+ * Sets current Page (internal).
*
* @param $page
*
- * @return self
- *
* @throws \InvalidArgumentException
+ *
+ * @return self
*/
public function setPage($page)
{
- if ((int)$page >= 0) {
+ if ((int) $page >= 0) {
$this->page = (int) $page;
} else {
- throw new \InvalidArgumentException('Page must be a positive number');
+ throw new \InvalidArgumentException(self::PAGE_NOT_VALID_EX_MSG);
}
return $this;
}
/**
- * Returns current page
+ * Returns current page.
*
* @return int
*/
@@ -1601,9 +1777,8 @@ public function getPage()
return $this->page;
}
-
/**
- * Returnd grid display data as rows - internal helper for templates
+ * Returnd grid display data as rows - internal helper for templates.
*
* @return mixed
*/
@@ -1613,17 +1788,23 @@ public function getRows()
}
/**
- * Return count of available pages
+ * Return count of available pages.
*
* @return float
*/
public function getPageCount()
{
- return ceil($this->getTotalCount() / $this->getLimit());
+ $pageCount = 1;
+ if ($this->getLimit() > 0) {
+ $pageCount = ceil($this->getTotalCount() / $this->getLimit());
+ }
+
+ // @todo why this should be a float?
+ return $pageCount;
}
/**
- * Returns count of filtred rows(items) from source
+ * Returns count of filtred rows(items) from source.
*
* @return mixed
*/
@@ -1633,18 +1814,18 @@ public function getTotalCount()
}
/**
- * Sets the max results of the grid
+ * Sets the max results of the grid.
*
* @param int $maxResults
*
- * @return self
- *
* @throws \InvalidArgumentException
+ *
+ * @return self
*/
public function setMaxResults($maxResults = null)
{
if ((is_int($maxResults) && $maxResults < 0) && $maxResults !== null) {
- throw new \InvalidArgumentException('Max results must be a positive number.');
+ throw new \InvalidArgumentException(self::NOT_VALID_MAX_RESULT_EX_MSG);
}
$this->maxResults = $maxResults;
@@ -1653,9 +1834,9 @@ public function setMaxResults($maxResults = null)
}
/**
- * Return true if the grid is filtered
+ * Return true if the grid is filtered.
*
- * @return boolean
+ * @return bool
*/
public function isFiltered()
{
@@ -1669,29 +1850,31 @@ public function isFiltered()
}
/**
- * Return true if if title panel is visible in template - internal helper
+ * Return true if if title panel is visible in template - internal helper.
*
* @return bool
*/
public function isTitleSectionVisible()
{
- if ($this->showTitles == true) {
+ if ($this->showTitles === true) {
foreach ($this->columns as $column) {
if ($column->getTitle() != '') {
return true;
}
}
}
+
+ return false;
}
/**
- * Return true if filter panel is visible in template - internal helper
+ * Return true if filter panel is visible in template - internal helper.
*
* @return bool
*/
public function isFilterSectionVisible()
{
- if ($this->showFilters == true) {
+ if ($this->showFilters === true) {
foreach ($this->columns as $column) {
if ($column->isFilterable() && $column->getType() != 'massaction' && $column->getType() != 'actions') {
return true;
@@ -1703,18 +1886,24 @@ public function isFilterSectionVisible()
}
/**
- * Return true if pager panel is visible in template - internal helper
+ * Return true if pager panel is visible in template - internal helper.
*
* @return bool return true if pager is visible
*/
public function isPagerSectionVisible()
{
+ $limits = $this->getLimits();
+
+ if (empty($limits)) {
+ return false;
+ }
+
// true when totalCount rows exceed the minimum pager limit
- return (min(array_keys($this->getLimits())) <= $this->totalCount);
+ return min(array_keys($limits)) < $this->totalCount;
}
/**
- * Hides Filters Panel
+ * Hides Filters Panel.
*
* @return self
*/
@@ -1726,7 +1915,7 @@ public function hideFilters()
}
/**
- * Hides Titles panel
+ * Hides Titles panel.
*
* @return self
*/
@@ -1738,9 +1927,9 @@ public function hideTitles()
}
/**
- * Adds Column Extension - internal helper
+ * Adds Column Extension - internal helper.
*
- * @param Column\Column $extension
+ * @param Column $extension
*
* @return self
*/
@@ -1752,7 +1941,7 @@ public function addColumnExtension($extension)
}
/**
- * Set a prefix title
+ * Set a prefix title.
*
* @param $prefixTitle string
*
@@ -1766,7 +1955,7 @@ public function setPrefixTitle($prefixTitle)
}
/**
- * Get the prefix title
+ * Get the prefix title.
*
* @return string
*/
@@ -1776,7 +1965,7 @@ public function getPrefixTitle()
}
/**
- * Set the no data message
+ * Set the no data message.
*
* @param $noDataMessage string
*
@@ -1790,7 +1979,7 @@ public function setNoDataMessage($noDataMessage)
}
/**
- * Get the no data message
+ * Get the no data message.
*
* @return string
*/
@@ -1800,7 +1989,7 @@ public function getNoDataMessage()
}
/**
- * Set the no result message
+ * Set the no result message.
*
* @param $noResultMessage string
*
@@ -1814,7 +2003,7 @@ public function setNoResultMessage($noResultMessage)
}
/**
- * Get the no result message
+ * Get the no result message.
*
* @return string
*/
@@ -1824,7 +2013,7 @@ public function getNoResultMessage()
}
/**
- * Sets a list of columns to hide when the grid is output
+ * Sets a list of columns to hide when the grid is output.
*
* @param array $columnIds
*
@@ -1839,7 +2028,7 @@ public function setHiddenColumns($columnIds)
/**
* Sets a list of columns to show when the grid is output
- * It acts as a mask; Other columns will be set as hidden
+ * It acts as a mask; Other columns will be set as hidden.
*
* @param array $columnIds
*
@@ -1853,7 +2042,7 @@ public function setVisibleColumns($columnIds)
}
/**
- * Sets on the visibility of columns
+ * Sets on the visibility of columns.
*
* @param string|array $columnIds
*
@@ -1869,7 +2058,7 @@ public function showColumns($columnIds)
}
/**
- * Sets off the visiblilty of columns
+ * Sets off the visiblilty of columns.
*
* @param string|array $columnIds
*
@@ -1885,9 +2074,9 @@ public function hideColumns($columnIds)
}
/**
- * Sets the size of the default action column
+ * Sets the size of the default action column.
*
- * @param integer $size
+ * @param int $size
*
* @return self
*/
@@ -1899,7 +2088,7 @@ public function setActionsColumnSize($size)
}
/**
- * Sets the title of the default action column
+ * Sets the title of the default action column.
*
* @param string $title
*
@@ -1913,17 +2102,17 @@ public function setActionsColumnTitle($title)
}
/**
- * Default delete action
+ * Default delete action.
*
- * @param $ids
+ * @param array $ids
*/
- public function deleteAction($ids, $actionAllKeys)
+ public function deleteAction(array $ids)
{
- $this->source->delete($ids, $actionAllKeys);
+ $this->source->delete($ids);
}
/**
- * Get a clone of the grid
+ * Get a clone of the grid.
*/
public function __clone()
{
@@ -1934,13 +2123,13 @@ public function __clone()
/****** HELPER ******/
/**
- * Redirects or Renders a view - helper function
+ * Redirects or Renders a view - helper function.
*
- * @param string|array $param1 The view name or an array of parameters to pass to the view
- * @param string|array $param2 The view name or an array of parameters to pass to the view
- * @param Response $response A response instance
+ * @param string|array $param1 The view name or an array of parameters to pass to the view
+ * @param string|array $param2 The view name or an array of parameters to pass to the view
+ * @param Response $response A response instance
*
- * @return Response A Response instance
+ * @return Response|array A Response instance
*/
public function getGridResponse($param1 = null, $param2 = null, Response $response = null)
{
@@ -1965,21 +2154,29 @@ public function getGridResponse($param1 = null, $param2 = null, Response $respon
$view = $param1;
}
- $parameters = array_merge(array('grid' => $this), $parameters);
+ $parameters = array_merge(['grid' => $this], $parameters);
if ($view === null) {
return $parameters;
} else {
- return $this->container->get('templating')->renderResponse($view, $parameters, $response);
+ $content = $this->twig->render($view, $parameters);
+
+ if (null === $response) {
+ $response = new Response();
+ }
+
+ $response->setContent($content);
+
+ return $response;
}
}
}
/**
- * Extract raw data of columns
+ * Extract raw data of columns.
*
- * @param string|array $columnNames The name of the extract columns. If null, all the columns are return.
- * @param boolean $namedIndexes If sets to true, named indexes will be used
+ * @param string|array $columnNames The name of the extract columns. If null, all the columns are return.
+ * @param bool $namedIndexes If sets to true, named indexes will be used
*
* @return array Raw data of columns
*/
@@ -1992,9 +2189,9 @@ public function getRawData($columnNames = null, $namedIndexes = true)
}
$columnNames = (array) $columnNames;
- $result = array();
+ $result = [];
foreach ($this->rows as $row) {
- $resultRow = array();
+ $resultRow = [];
foreach ($columnNames as $columnName) {
if ($namedIndexes) {
$resultRow[$columnName] = $row->getField($columnName);
@@ -2010,22 +2207,23 @@ public function getRawData($columnNames = null, $namedIndexes = true)
}
/**
- * Returns an array of the active filters of the grid stored in session
+ * Returns an array of the active filters of the grid stored in session.
*
- * @return Filter[]
* @throws \Exception
+ *
+ * @return Filter[]
*/
public function getFilters()
{
if ($this->hash === null) {
- throw new \Exception('getFilters method is only available in the manipulate callback function or after the call of the method isRedirected of the grid.');
+ throw new \Exception(self::GET_FILTERS_NO_REQUEST_HANDLED_EX_MSG);
}
if ($this->sessionFilters === null) {
- $this->sessionFilters = array();
+ $this->sessionFilters = [];
$session = $this->sessionData;
- $requestQueries = array(
+ $requestQueries = [
self::REQUEST_QUERY_MASS_ACTION_ALL_KEYS_SELECTED,
self::REQUEST_QUERY_MASS_ACTION,
self::REQUEST_QUERY_EXPORT,
@@ -2035,7 +2233,7 @@ public function getFilters()
self::REQUEST_QUERY_TEMPLATE,
self::REQUEST_QUERY_RESET,
MassActionColumn::ID,
- );
+ ];
foreach ($requestQueries as $request_query) {
unset($session[$request_query]);
@@ -2049,7 +2247,7 @@ public function getFilters()
$operator = $this->getColumn($columnId)->getDefaultOperator();
}
- if (! isset($sessionFilter['to'])) {
+ if (!isset($sessionFilter['to']) && isset($sessionFilter['from'])) {
$sessionFilter = $sessionFilter['from'];
}
@@ -2061,17 +2259,19 @@ public function getFilters()
}
/**
- * Returns the filter of a column stored in session
+ * Returns the filter of a column stored in session.
*
* @param string $columnId
- * Id of the column
- * @return Filter
+ * Id of the column
+ *
* @throws \Exception
+ *
+ * @return Filter
*/
public function getFilter($columnId)
{
if ($this->hash === null) {
- throw new \Exception('getFilters method is only available in the manipulate callback function or after the call of the method isRedirected of the grid.');
+ throw new \Exception(self::GET_FILTERS_NO_REQUEST_HANDLED_EX_MSG);
}
$sessionFilters = $this->getFilters();
@@ -2083,16 +2283,146 @@ public function getFilter($columnId)
* A filter of the column is stored in session ?
*
* @param string $columnId
- * Id of the column
- * @return boolean
+ * Id of the column
+ *
* @throws \Exception
+ *
+ * @return bool
*/
public function hasFilter($columnId)
{
if ($this->hash === null) {
- throw new \Exception('hasFilters method is only available in the manipulate callback function or after the call of the method isRedirected of the grid.');
+ throw new \Exception(self::HAS_FILTER_NO_REQUEST_HANDLED_EX_MSG);
}
- return getFilter($columnId) !== null;
+ return $this->getFilter($columnId) !== null;
+ }
+
+ /**
+ * Get default order (e.g. my_column_id|asc).
+ *
+ * @return string
+ */
+ public function getDefaultOrder()
+ {
+ return $this->defaultOrder;
+ }
+
+ /**
+ * Get the value of maxResults
+ *
+ * @return int
+ */
+ public function getMaxResults()
+ {
+ return $this->maxResults;
+ }
+
+ /**
+ * Get the value of lazyAddColumn
+ */
+ public function getLazyAddColumn()
+ {
+ return $this->lazyAddColumn;
+ }
+
+ /**
+ * Get default Tweak.
+ *
+ * @return string
+ */
+ public function getDefaultTweak()
+ {
+ return $this->defaultTweak;
+ }
+
+ /**
+ * Get the value of lazyVisibleColumns
+ */
+ public function getLazyVisibleColumns()
+ {
+ return $this->lazyVisibleColumns;
+ }
+
+ /**
+ * Get the value of lazyHideShowColumns
+ */
+ public function getLazyHideShowColumns()
+ {
+ return $this->lazyHideShowColumns;
+ }
+
+ /**
+ * Get the value of actionsColumnSize
+ */
+ public function getActionsColumnSize()
+ {
+ return $this->actionsColumnSize;
+ }
+
+ /**
+ * Get the value of actionsColumnTitle
+ */
+ public function getActionsColumnTitle()
+ {
+ return $this->actionsColumnTitle;
+ }
+
+ /**
+ * Get the value of showFilters
+ *
+ * @return bool
+ */
+ public function getShowFilters()
+ {
+ return $this->showFilters;
+ }
+
+ /**
+ * Get the value of showTitles
+ *
+ * @return bool
+ */
+ public function getShowTitles()
+ {
+ return $this->showTitles;
+ }
+
+ /**
+ * Get the value of lazyHiddenColumns
+ */
+ public function getLazyHiddenColumns()
+ {
+ return $this->lazyHiddenColumns;
+ }
+
+ /**
+ * Get the value of newSession
+ *
+ * @return bool
+ */
+ public function getNewSession()
+ {
+ return $this->newSession;
+ }
+
+ /**
+ * Get default filters.
+ *
+ * @return array
+ */
+ public function getDefaultFilters()
+ {
+ return $this->defaultFilters;
+ }
+
+ /**
+ * Get permanent filters.
+ *
+ * @return array
+ */
+ public function getPermanentFilters()
+ {
+ return $this->permanentFilters;
}
}
diff --git a/Grid/GridBuilder.php b/Grid/GridBuilder.php
new file mode 100644
index 00000000..603ad5df
--- /dev/null
+++ b/Grid/GridBuilder.php
@@ -0,0 +1,133 @@
+container = $container;
+ $this->factory = $factory;
+ $this->securityContext = $securityContext;
+ $this->twig = $twig;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function add($name, $type, array $options = [])
+ {
+ if (!$type instanceof Column) {
+ if (!is_string($type)) {
+ throw new UnexpectedTypeException($type, 'string, APY\DataGridBundle\Grid\Column\Column');
+ }
+
+ $type = $this->factory->createColumn($name, $type, $options);
+ }
+
+ $this->columns[$name] = $type;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function get($name)
+ {
+ if (!$this->has($name)) {
+ throw new InvalidArgumentException(sprintf('The column with the name "%s" does not exist.', $name));
+ }
+
+ $column = $this->columns[$name];
+
+ return $column;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function has($name)
+ {
+ return isset($this->columns[$name]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function remove($name)
+ {
+ unset($this->columns[$name]);
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getGrid()
+ {
+ $config = $this->getGridConfig();
+
+ $grid = new Grid($this->container, $this->securityContext, $this->twig, $config->getName(), $config);
+
+ foreach ($this->columns as $column) {
+ $grid->addColumn($column);
+ }
+
+ if (!empty($this->actions)) {
+ foreach ($this->actions as $columnId => $actions) {
+ foreach ($actions as $action) {
+ $grid->addRowAction($action);
+ }
+ }
+ }
+
+ $grid->initialize();
+
+ return $grid;
+ }
+}
diff --git a/Grid/GridBuilderInterface.php b/Grid/GridBuilderInterface.php
new file mode 100644
index 00000000..25a3dbec
--- /dev/null
+++ b/Grid/GridBuilderInterface.php
@@ -0,0 +1,58 @@
+name = $name;
+ $this->options = $options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSource()
+ {
+ return $this->source;
+ }
+
+ /**
+ * Set Source.
+ *
+ * @param Source $source
+ *
+ * @return $this
+ */
+ public function setSource(Source $source)
+ {
+ $this->source = $source;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType()
+ {
+ return $this->type;
+ }
+
+ /**
+ * Set Type.
+ *
+ * @param GridTypeInterface $type
+ *
+ * @return $this
+ */
+ public function setType(GridTypeInterface $type)
+ {
+ $this->type = $type;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRoute()
+ {
+ return $this->route;
+ }
+
+ /**
+ * Set Route.
+ *
+ * @param mixed $route
+ *
+ * @return $this
+ */
+ public function setRoute($route)
+ {
+ $this->route = $route;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRouteParameters()
+ {
+ return $this->routeParameters;
+ }
+
+ /**
+ * Set RouteParameters.
+ *
+ * @param array $routeParameters
+ *
+ * @return $this
+ */
+ public function setRouteParameters(array $routeParameters)
+ {
+ $this->routeParameters = $routeParameters;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isPersisted()
+ {
+ return $this->persistence;
+ }
+
+ /**
+ * Set Persistence.
+ *
+ * @param mixed $persistence
+ *
+ * @return $this
+ */
+ public function setPersistence($persistence)
+ {
+ $this->persistence = $persistence;
+
+ return $this;
+ }
+
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPersistence()
+ {
+ return $this->persistence;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getPage()
+ {
+ return $this->page;
+ }
+
+ /**
+ * Set Page.
+ *
+ * @param int $page
+ *
+ * @return $this
+ */
+ public function setPage($page)
+ {
+ $this->page = $page;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOptions()
+ {
+ return $this->options;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasOption($name)
+ {
+ return array_key_exists($name, $this->options);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOption($name, $default = null)
+ {
+ return array_key_exists($name, $this->options) ? $this->options[$name] : $default;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMaxPerPage()
+ {
+ return $this->limit;
+ }
+
+ /**
+ * Set Limit.
+ *
+ * @param int $limit
+ *
+ * @return $this
+ */
+ public function setMaxPerPage($limit)
+ {
+ $this->limit = $limit;
+
+ return $this;
+ }
+
+ /**
+ * Get MaxResults.
+ *
+ * @return int
+ */
+ public function getMaxResults()
+ {
+ return $this->maxResults;
+ }
+
+ /**
+ * Set MaxResults.
+ *
+ * @param int $maxResults
+ *
+ * @return $this
+ */
+ public function setMaxResults($maxResults)
+ {
+ $this->maxResults = $maxResults;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSortable()
+ {
+ return $this->sortable;
+ }
+
+ /**
+ * Set Sortable.
+ *
+ * @param bool $sortable
+ *
+ * @return $this
+ */
+ public function setSortable($sortable)
+ {
+ $this->sortable = $sortable;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isFilterable()
+ {
+ return $this->filterable;
+ }
+
+ /**
+ * Set Filterable.
+ *
+ * @param bool $filterable
+ *
+ * @return $this
+ */
+ public function setFilterable($filterable)
+ {
+ $this->filterable = $filterable;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getOrder()
+ {
+ return $this->order;
+ }
+
+ /**
+ * Set Order.
+ *
+ * @param string $order
+ *
+ * @return $this
+ */
+ public function setOrder($order)
+ {
+ $this->order = $order;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSortBy()
+ {
+ return $this->sortBy;
+ }
+
+ /**
+ * Set SortBy.
+ *
+ * @param string $sortBy
+ *
+ * @return $this
+ */
+ public function setSortBy($sortBy)
+ {
+ $this->sortBy = $sortBy;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getGroupBy()
+ {
+ return $this->groupBy;
+ }
+
+ /**
+ * Set GroupBy.
+ *
+ * @param array|string $groupBy
+ *
+ * @return $this
+ */
+ public function setGroupBy($groupBy)
+ {
+ $this->groupBy = $groupBy;
+
+ return $this;
+ }
+
+ /**
+ * @param RowActionInterface $action
+ *
+ * @return $this
+ */
+ public function addAction(RowActionInterface $action)
+ {
+ $this->actions[$action->getColumn()][] = $action;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getActions()
+ {
+ return $this->actions;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getGridConfig()
+ {
+ $config = clone $this;
+
+ return $config;
+ }
+}
diff --git a/Grid/GridConfigBuilderInterface.php b/Grid/GridConfigBuilderInterface.php
new file mode 100644
index 00000000..39e14d8a
--- /dev/null
+++ b/Grid/GridConfigBuilderInterface.php
@@ -0,0 +1,18 @@
+container = $container;
+ $this->registry = $registry;
+ $this->securityContext = $securityContext;
+ $this->twig = $twig;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function create($type = null, Source $source = null, array $options = [])
+ {
+ return $this->createBuilder($type, $source, $options)->getGrid();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createBuilder($type = 'grid', Source $source = null, array $options = [])
+ {
+ $type = $this->resolveType($type);
+ $options = $this->resolveOptions($type, $source, $options);
+
+ $builder = new GridBuilder($this->container, $this->securityContext, $this->twig, $this, $type->getName(), $options);
+ $builder->setType($type);
+
+ $type->buildGrid($builder, $options);
+
+ return $builder;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createColumn($name, $type, array $options = [])
+ {
+ if (!$type instanceof Column) {
+ if (!is_string($type)) {
+ throw new UnexpectedTypeException($type, 'string, APY\DataGridBundle\Grid\Column\Column');
+ }
+
+ $column = clone $this->registry->getColumn($type);
+
+ $column->__initialize(array_merge([
+ 'id' => $name,
+ 'title' => $name,
+ 'field' => $name,
+ 'source' => true,
+ ], $options));
+ } else {
+ $column = $type;
+ $column->setId($name);
+ }
+
+ return $column;
+ }
+
+ /**
+ * Returns an instance of type.
+ *
+ * @param string|GridTypeInterface $type The type of the grid
+ *
+ * @return GridTypeInterface
+ */
+ private function resolveType($type)
+ {
+ if (!$type instanceof GridTypeInterface) {
+ if (!is_string($type)) {
+ throw new UnexpectedTypeException($type, 'string, APY\DataGridBundle\Grid\GridTypeInterface');
+ }
+
+ $type = $this->registry->getType($type);
+ }
+
+ return $type;
+ }
+
+ /**
+ * Returns the options resolved.
+ *
+ * @param GridTypeInterface $type
+ * @param Source $source
+ * @param array $options
+ *
+ * @return array
+ */
+ private function resolveOptions(GridTypeInterface $type, Source $source = null, array $options = []): array
+ {
+ $resolver = new OptionsResolver();
+
+ $type->configureOptions($resolver);
+
+ if (null !== $source && !isset($options['source'])) {
+ $options['source'] = $source;
+ }
+
+ $options = $resolver->resolve($options);
+
+ return $options;
+ }
+}
diff --git a/Grid/GridFactoryInterface.php b/Grid/GridFactoryInterface.php
new file mode 100644
index 00000000..29fba47b
--- /dev/null
+++ b/Grid/GridFactoryInterface.php
@@ -0,0 +1,47 @@
+container = $container;
- $this->grids = new \SplObjectStorage();
+ $this->twig= $twig;
+ $this->grids = new SplObjectStorage();
}
- public function getIterator()
+ public function getIterator(): \Traversable
{
return $this->grids;
}
- public function count()
+ public function count(): int
{
return $this->grids->count();
}
/**
* @param mixed $id
+ *
* @return Grid
*/
- public function createGrid($id = null)
+ public function createGrid($id = null): Grid
{
$grid = $this->container->get('grid');
@@ -60,13 +75,13 @@ public function createGrid($id = null)
return $grid;
}
- public function isReadyForRedirect()
+ public function isReadyForRedirect(): bool
{
if ($this->grids->count() == 0) {
- throw new \RuntimeException('No grid has been added to the manager.');
+ throw new RuntimeException(self::NO_GRID_EX_MSG);
}
- $checkHash = array();
+ $checkHash = [];
$isReadyForRedirect = false;
$this->grids->rewind();
@@ -85,7 +100,7 @@ public function isReadyForRedirect()
}
if (in_array($grid->getHash(), $checkHash)) {
- throw new \RuntimeException('Some grids seem similar. Please set an Indentifier for your grids.');
+ throw new RuntimeException(self::SAME_GRID_HASH_EX_MSG);
}
$checkHash[] = $grid->getHash();
@@ -96,20 +111,20 @@ public function isReadyForRedirect()
return $isReadyForRedirect;
}
- public function isReadyForExport()
+ public function isReadyForExport(): bool
{
if ($this->grids->count() == 0) {
- throw new \RuntimeException('No grid has been added to the manager.');
+ throw new RuntimeException(self::NO_GRID_EX_MSG);
}
- $checkHash = array();
+ $checkHash = [];
$this->grids->rewind();
while ($this->grids->valid()) {
$grid = $this->grids->current();
if (in_array($grid->getHash(), $checkHash)) {
- throw new \RuntimeException('Some grids seem similar. Please set an Indentifier for your grids.');
+ throw new RuntimeException(self::SAME_GRID_HASH_EX_MSG);
}
$checkHash[] = $grid->getHash();
@@ -126,7 +141,7 @@ public function isReadyForExport()
return false;
}
- public function isMassActionRedirect()
+ public function isMassActionRedirect(): bool
{
$this->grids->rewind();
while ($this->grids->valid()) {
@@ -147,11 +162,11 @@ public function isMassActionRedirect()
/**
* Renders a view.
*
- * @param string|array $param1 The view name or an array of parameters to pass to the view
- * @param string|array $param1 The view name or an array of parameters to pass to the view
- * @param Response $response A response instance
+ * @param string|array $param1 The view name or an array of parameters to pass to the view
+ * @param string|array $param2 The view name or an array of parameters to pass to the view
+ * @param Response|null $response A response instance
*
- * @return Response A Response instance
+ * @return Response|array A Response instance
*/
public function getGridManagerResponse($param1 = null, $param2 = null, Response $response = null)
{
@@ -179,16 +194,24 @@ public function getGridManagerResponse($param1 = null, $param2 = null, Response
$i = 1;
$this->grids->rewind();
while ($this->grids->valid()) {
- $parameters = array_merge(array('grid'.$i => $this->grids->current()), $parameters);
+ $parameters = array_merge(['grid' . $i => $this->grids->current()], $parameters);
$this->grids->next();
- $i++;
+ ++$i;
}
if ($view === null) {
return $parameters;
}
- return $this->container->get('templating')->renderResponse($view, $parameters, $response);
+ $content = $this->twig->render($view, $parameters);
+
+ if (null === $response) {
+ $response = new Response();
+ }
+
+ $response->setContent($content);
+
+ return $response;
}
}
@@ -201,4 +224,28 @@ public function setRouteUrl($routeUrl)
{
$this->routeUrl = $routeUrl;
}
+
+ /**
+ * Get the value of grids
+ */
+ public function getGrids()
+ {
+ return $this->grids;
+ }
+
+ /**
+ * Get the value of exportGrid
+ */
+ public function getExportGrid()
+ {
+ return $this->exportGrid;
+ }
+
+ /**
+ * Get the value of massActionGrid
+ */
+ public function getMassActionGrid()
+ {
+ return $this->massActionGrid;
+ }
}
diff --git a/Grid/GridRegistry.php b/Grid/GridRegistry.php
new file mode 100644
index 00000000..b39f69af
--- /dev/null
+++ b/Grid/GridRegistry.php
@@ -0,0 +1,123 @@
+getName();
+
+ if ($this->hasType($name)) {
+ throw new TypeAlreadyExistsException($name);
+ }
+
+ $this->types[$name] = $type;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getType($name)
+ {
+ if (!$this->hasType($name)) {
+ throw new TypeNotFoundException($name);
+ }
+
+ $type = $this->types[$name];
+
+ return $type;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasType($name)
+ {
+ if (isset($this->types[$name])) {
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Add a column type.
+ *
+ * @param Column $column
+ *
+ * @return $this
+ */
+ public function addColumn(Column $column)
+ {
+ $type = $column->getType();
+
+ if ($this->hasColumn($type)) {
+ throw new ColumnAlreadyExistsException($type);
+ }
+
+ $this->columns[$type] = $column;
+
+ return $this;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getColumn($type)
+ {
+ if (!$this->hasColumn($type)) {
+ throw new ColumnNotFoundException($type);
+ }
+
+ $column = $this->columns[$type];
+
+ return $column;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasColumn($type)
+ {
+ if (isset($this->columns[$type])) {
+ return true;
+ }
+
+ return false;
+ }
+}
diff --git a/Grid/GridRegistryInterface.php b/Grid/GridRegistryInterface.php
new file mode 100644
index 00000000..750259ed
--- /dev/null
+++ b/Grid/GridRegistryInterface.php
@@ -0,0 +1,51 @@
+showOnlySourceColumns = $showOnlySourceColumns;
}
- public function accept()
+ public function accept(): bool
{
$current = $this->getInnerIterator()->current();
diff --git a/Grid/Helper/ORMCountWalker.php b/Grid/Helper/ORMCountWalker.php
index 32b45832..9bfc3a99 100644
--- a/Grid/Helper/ORMCountWalker.php
+++ b/Grid/Helper/ORMCountWalker.php
@@ -1,6 +1,7 @@
* @copyright Copyright (c) 2010 David Abdemoulaie (http://hobodave.com/)
* @license http://hobodave.com/license.txt New BSD License
@@ -40,21 +41,19 @@ class ORMCountWalker extends TreeWalkerAdapter
*
* @param SelectStatement $AST
*
- * @return void
- *
* @throws \RuntimeException
*/
public function walkSelectStatement(SelectStatement $AST)
{
- $rootComponents = array();
- foreach ($this->_getQueryComponents() AS $dqlAlias => $qComp) {
+ $rootComponents = [];
+ foreach ($this->_getQueryComponents() as $dqlAlias => $qComp) {
if (array_key_exists('parent', $qComp) && $qComp['parent'] === null && $qComp['nestingLevel'] == 0) {
- $rootComponents[] = array($dqlAlias => $qComp);
+ $rootComponents[] = [$dqlAlias => $qComp];
}
}
if (count($rootComponents) > 1) {
- throw new \RuntimeException("Cannot count query which selects two FROM components, cannot make distinction");
+ throw new \RuntimeException('Cannot count query which selects two FROM components, cannot make distinction');
}
$root = reset($rootComponents);
@@ -67,10 +66,9 @@ public function walkSelectStatement(SelectStatement $AST)
);
$pathExpression->type = PathExpression::TYPE_STATE_FIELD;
-
// Remove the variables which are not used by other clauses
foreach ($AST->selectClause->selectExpressions as $key => $selectExpression) {
- if ($selectExpression->fieldIdentificationVariable == null) {
+ if ($selectExpression->fieldIdentificationVariable === null) {
unset($AST->selectClause->selectExpressions[$key]);
} elseif ($selectExpression->expression instanceof PathExpression) {
$groupByClause[] = $selectExpression->expression;
diff --git a/Grid/Mapping/Column.php b/Grid/Mapping/Column.php
index a805f3f2..64203434 100644
--- a/Grid/Mapping/Column.php
+++ b/Grid/Mapping/Column.php
@@ -23,7 +23,7 @@ class Column
public function __construct($metadata)
{
$this->metadata = $metadata;
- $this->groups = isset($metadata['groups']) ? (array) $metadata['groups'] : array('default');
+ $this->groups = isset($metadata['groups']) ? (array) $metadata['groups'] : ['default'];
}
public function getMetadata()
diff --git a/Grid/Mapping/Driver/Annotation.php b/Grid/Mapping/Driver/Annotation.php
index 61463936..a414e09e 100644
--- a/Grid/Mapping/Driver/Annotation.php
+++ b/Grid/Mapping/Driver/Annotation.php
@@ -29,7 +29,7 @@ class Annotation implements DriverInterface
public function __construct($reader)
{
$this->reader = $reader;
- $this->columns = $this->fields = $this->loaded = $this->groupBy = $this->filterable = $this->sortable = array();
+ $this->columns = $this->fields = $this->loaded = $this->groupBy = $this->filterable = $this->sortable = [];
}
public function getClassColumns($class, $group = 'default')
@@ -48,14 +48,16 @@ public function getFieldsMetadata($class, $group = 'default')
public function getGroupBy($class, $group = 'default')
{
- return isset($this->groupBy[$class][$group]) ? $this->groupBy[$class][$group] : array();
+ return isset($this->groupBy[$class][$group]) ? $this->groupBy[$class][$group] : [];
}
protected function loadMetadataFromReader($className, $group = 'default')
{
- if (isset($this->loaded[$className][$group])) return;
+ if (isset($this->loaded[$className][$group])) {
+ return;
+ }
- $reflectionCollection = array();
+ $reflectionCollection = [];
$reflectionCollection[] = $reflection = new \ReflectionClass($className);
while (false !== $reflection = $reflection->getParentClass()) {
@@ -70,7 +72,7 @@ protected function loadMetadataFromReader($className, $group = 'default')
}
foreach ($reflection->getProperties() as $property) {
- $this->fields[$className][$group][$property->getName()] = array();
+ $this->fields[$className][$group][$property->getName()] = [];
foreach ($this->reader->getPropertyAnnotations($property) as $class) {
$this->getMetadataFromClassProperty($className, $class, $property->getName(), $group);
@@ -109,7 +111,7 @@ protected function getMetadataFromClassProperty($className, $class, $name = null
if ($name === null) { // Class Column annotation
if (isset($metadata['id'])) {
$metadata['source'] = false;
- $this->fields[$className][$group][$metadata['id']] = array();
+ $this->fields[$className][$group][$metadata['id']] = [];
} else {
throw new \Exception(sprintf('Missing parameter `id` in annotations for extra column of class %s', $className));
}
@@ -129,7 +131,7 @@ protected function getMetadataFromClassProperty($className, $class, $name = null
// Check the group of the annotation and don't override if an annotation with the group have already been defined
if (isset($metadata['groups']) && !in_array($group, (array) $metadata['groups'])
- || isset($this->fields[$className][$group][$metadata['id']]['groups'])) {
+ || isset($this->fields[$className][$group][$metadata['id']]['groups'])) {
return;
}
diff --git a/Grid/Mapping/Metadata/DriverHeap.php b/Grid/Mapping/Metadata/DriverHeap.php
index 280fe6cf..10d37641 100644
--- a/Grid/Mapping/Metadata/DriverHeap.php
+++ b/Grid/Mapping/Metadata/DriverHeap.php
@@ -17,15 +17,16 @@
class DriverHeap extends \SplPriorityQueue
{
/**
- * (non-PHPdoc)
+ * (non-PHPdoc).
+ *
* @see SplPriorityQueue::compare()
*/
- public function compare($priority1, $priority2)
- {
- if ($priority1 === $priority2) {
- return 0;
- }
+ public function compare($priority1, $priority2): int
+ {
+ if ($priority1 === $priority2) {
+ return 0;
+ }
- return $priority1 > $priority2 ? -1 : 1;
- }
+ return $priority1 > $priority2 ? -1 : 1;
+ }
}
diff --git a/Grid/Mapping/Metadata/Manager.php b/Grid/Mapping/Metadata/Manager.php
index dd908147..491127a0 100644
--- a/Grid/Mapping/Metadata/Manager.php
+++ b/Grid/Mapping/Metadata/Manager.php
@@ -33,6 +33,7 @@ public function addDriver($driver, $priority)
/**
* @todo remove this hack
+ *
* @return \APY\DataGridBundle\Grid\Mapping\Metadata\DriverHeap
*/
public function getDrivers()
@@ -44,7 +45,7 @@ public function getMetadata($className, $group = 'default')
{
$metadata = new Metadata();
- $columns = $fieldsMetadata = $groupBy = array();
+ $columns = $fieldsMetadata = $groupBy = [];
foreach ($this->getDrivers() as $driver) {
$columns = array_merge($columns, $driver->getClassColumns($className, $group));
@@ -52,12 +53,12 @@ public function getMetadata($className, $group = 'default')
$groupBy = array_merge($groupBy, $driver->getGroupBy($className, $group));
}
- $mappings = $cols = array();
+ $mappings = $cols = [];
foreach ($columns as $fieldName) {
- $map = array();
+ $map = [];
- foreach($fieldsMetadata as $field) {
+ foreach ($fieldsMetadata as $field) {
if (isset($field[$fieldName]) && (!isset($field[$fieldName]['groups']) || in_array($group, (array) $field[$fieldName]['groups']))) {
$map = array_merge($map, $field[$fieldName]);
}
diff --git a/Grid/Mapping/Metadata/Metadata.php b/Grid/Mapping/Metadata/Metadata.php
index a48280f2..37373815 100644
--- a/Grid/Mapping/Metadata/Metadata.php
+++ b/Grid/Mapping/Metadata/Metadata.php
@@ -77,9 +77,12 @@ public function getName()
/**
* @todo move to another place
+ *
* @param $columnExtensions
- * @return \SplObjectStorage
+ *
* @throws \Exception
+ *
+ * @return \SplObjectStorage
*/
public function getColumnsFromMapping($columnExtensions)
{
@@ -89,16 +92,24 @@ public function getColumnsFromMapping($columnExtensions)
$params = $this->getFieldMapping($value);
$type = $this->getFieldMappingType($value);
- /** todo move available extensions from columns */
+ /* todo move available extensions from columns */
if ($columnExtensions->hasExtensionForColumnType($type)) {
$column = clone $columnExtensions->getExtensionForColumnType($type);
$column->__initialize($params);
$columns->attach($column);
} else {
- throw new \Exception(sprintf("No suitable Column Extension found for column type: %s", $type));
+ throw new \Exception(sprintf('No suitable Column Extension found for column type: %s', $type));
}
}
return $columns;
}
+
+ /**
+ * Get the value of fieldsMappings
+ */
+ public function getFieldsMappings()
+ {
+ return $this->fieldsMappings;
+ }
}
diff --git a/Grid/Mapping/Source.php b/Grid/Mapping/Source.php
index 49540130..e5ff5b30 100644
--- a/Grid/Mapping/Source.php
+++ b/Grid/Mapping/Source.php
@@ -23,13 +23,13 @@ class Source
protected $groups;
protected $groupBy;
- public function __construct($metadata = array())
+ public function __construct($metadata = [])
{
- $this->columns = (isset($metadata['columns']) && $metadata['columns'] != '') ? array_map('trim', explode(',', $metadata['columns'])) : array();
+ $this->columns = (isset($metadata['columns']) && $metadata['columns'] != '') ? array_map('trim', explode(',', $metadata['columns'])) : [];
$this->filterable = isset($metadata['filterable']) ? $metadata['filterable'] : true;
$this->sortable = isset($metadata['sortable']) ? $metadata['sortable'] : true;
- $this->groups = (isset($metadata['groups']) && $metadata['groups'] != '') ? (array) $metadata['groups'] : array('default');
- $this->groupBy = (isset($metadata['groupBy']) && $metadata['groupBy'] != '') ? (array) $metadata['groupBy'] : array();
+ $this->groups = (isset($metadata['groups']) && $metadata['groups'] != '') ? (array) $metadata['groups'] : ['default'];
+ $this->groupBy = (isset($metadata['groupBy']) && $metadata['groupBy'] != '') ? (array) $metadata['groupBy'] : [];
}
public function getColumns()
@@ -61,4 +61,12 @@ public function getGroupBy()
{
return $this->groupBy;
}
+
+ /**
+ * Get the value of sortable
+ */
+ public function getSortable()
+ {
+ return $this->sortable;
+ }
}
diff --git a/Grid/Row.php b/Grid/Row.php
index 6f6263cb..00a2d855 100644
--- a/Grid/Row.php
+++ b/Grid/Row.php
@@ -12,27 +12,56 @@
namespace APY\DataGridBundle\Grid;
+use Doctrine\ORM\EntityRepository;
+
class Row
{
+ /** @var array */
protected $fields;
+
+ /** @var string */
protected $class;
+
+ /** @var string */
protected $color;
+
+ /** @var string|null */
protected $legend;
+
+ /** @var mixed */
protected $primaryField;
+
+ /** @var mixed */
protected $entity;
+
+ /** @var EntityRepository */
protected $repository;
public function __construct()
{
- $this->fields = array();
+ $this->fields = [];
$this->color = '';
}
- public function setRepository($repository)
+ /**
+ * @param EntityRepository $repository
+ */
+ public function setRepository(EntityRepository $repository)
{
$this->repository = $repository;
}
+ /**
+ * @return EntityRepository
+ */
+ public function getRepository()
+ {
+ return $this->repository;
+ }
+
+ /**
+ * @return null|object
+ */
public function getEntity()
{
$primaryKeyValue = current($this->getPrimaryKeyValue());
@@ -40,87 +69,151 @@ public function getEntity()
return $this->repository->find($primaryKeyValue);
}
- public function setField($rowId, $value)
+ /**
+ * @return array
+ */
+ public function getPrimaryKeyValue()
{
- $this->fields[$rowId] = $value;
+ $primaryFieldValue = $this->getPrimaryFieldValue();
- return $this;
+ if (is_array($primaryFieldValue)) {
+ return $primaryFieldValue;
+ }
+
+ // @todo: is that correct? shouldn't be [$this->primaryField => $primaryFieldValue] ??
+ return ['id' => $primaryFieldValue];
}
- public function getField($rowId)
+ /**
+ * @throws \InvalidArgumentException
+ *
+ * @return array|mixed
+ */
+ public function getPrimaryFieldValue()
{
- return isset($this->fields[$rowId]) ? $this->fields[$rowId] : '';
+ if (null === $this->primaryField) {
+ throw new \InvalidArgumentException('Primary column must be defined');
+ }
+
+ if (is_array($this->primaryField)) {
+ return array_intersect_key($this->fields, array_flip($this->primaryField));
+ }
+
+ if (!isset($this->fields[$this->primaryField])) {
+ throw new \InvalidArgumentException('Primary field not added to fields');
+ }
+
+ return $this->fields[$this->primaryField];
}
- public function setClass($class)
+ /**
+ * @param mixed $primaryField
+ *
+ * @return $this
+ */
+ public function setPrimaryField($primaryField)
{
- $this->class = $class;
+ $this->primaryField = $primaryField;
return $this;
}
- public function getClass()
+ /**
+ * @return mixed
+ */
+ public function getPrimaryField()
{
- return $this->class;
+ return $this->primaryField;
}
- public function setColor($color)
+ /**
+ * @param mixed $columnId
+ * @param mixed $value
+ *
+ * @return $this
+ */
+ public function setField($columnId, $value)
{
- $this->color = $color;
+ $this->fields[$columnId] = $value;
return $this;
}
- public function getColor()
+ /**
+ * @param mixed $columnId
+ *
+ * @return mixed
+ */
+ public function getField($columnId)
{
- return $this->color;
+ return isset($this->fields[$columnId]) ? $this->fields[$columnId] : '';
}
- public function setLegend($legend)
+ /**
+ * @return array
+ */
+ public function getFields()
{
- $this->legend = $legend;
+ return $this->fields;
+ }
+
+ /**
+ * @param string $class
+ *
+ * @return $this
+ */
+ public function setClass($class)
+ {
+ $this->class = $class;
return $this;
}
- public function getLegend()
+ /**
+ * @return string
+ */
+ public function getClass()
{
- return $this->legend;
+ return $this->class;
}
- public function setPrimaryField($primaryField)
+ /**
+ * @param string $color
+ *
+ * @return $this
+ */
+ public function setColor($color)
{
- $this->primaryField = $primaryField;
+ $this->color = $color;
return $this;
}
- public function getPrimaryField()
+ /**
+ * @return string
+ */
+ public function getColor()
{
- return $this->primaryField;
+ return $this->color;
}
- public function getPrimaryFieldValue()
+ /**
+ * @param string $legend
+ *
+ * @return $this
+ */
+ public function setLegend($legend)
{
- if (null === $this->primaryField) {
- throw new \InvalidArgumentException('Primary column must be defined');
- }
-
- if (is_array($this->primaryField)) {
- return array_intersect_key($this->fields, array_flip($this->primaryField));
- }
+ $this->legend = $legend;
- return $this->fields[$this->primaryField];
+ return $this;
}
- public function getPrimaryKeyValue()
+ /**
+ * @return string|null
+ */
+ public function getLegend()
{
- $primaryField = $this->getPrimaryFieldValue();
-
- if (is_array($primaryField)) {
- return $primaryField;
- }
-
- return array('id' => $primaryField);
+ return $this->legend;
}
}
diff --git a/Grid/Rows.php b/Grid/Rows.php
index d2039f9d..fbc88dcf 100644
--- a/Grid/Rows.php
+++ b/Grid/Rows.php
@@ -14,12 +14,13 @@
class Rows implements \IteratorAggregate, \Countable
{
- /**
- * @var \SplObjectStorage $rows
- */
+ /** @var \SplObjectStorage */
protected $rows;
- public function __construct(array $rows = array())
+ /**
+ * @param array $rows
+ */
+ public function __construct(array $rows = [])
{
$this->rows = new \SplObjectStorage();
@@ -29,18 +30,20 @@ public function __construct(array $rows = array())
}
/**
- * (non-PHPdoc)
+ * (non-PHPdoc).
+ *
* @see IteratorAggregate::getIterator()
*/
- public function getIterator()
+ public function getIterator(): \Traversable
{
return $this->rows;
}
/**
- * Add row
+ * Add row.
*
* @param Row $row
+ *
* @return Rows
*/
public function addRow(Row $row)
@@ -51,16 +54,17 @@ public function addRow(Row $row)
}
/**
- * (non-PHPdoc)
+ * (non-PHPdoc).
+ *
* @see Countable::count()
*/
- public function count()
+ public function count(): int
{
return $this->rows->count();
}
/**
- * Returns the iterator as an array
+ * Returns the iterator as an array.
*
* @return array
*/
diff --git a/Grid/Source/Document.php b/Grid/Source/Document.php
index bc6ed134..c14d4825 100644
--- a/Grid/Source/Document.php
+++ b/Grid/Source/Document.php
@@ -14,9 +14,12 @@
namespace APY\DataGridBundle\Grid\Source;
-use APY\DataGridBundle\Grid\Rows;
-use APY\DataGridBundle\Grid\Row;
use APY\DataGridBundle\Grid\Column\Column;
+use APY\DataGridBundle\Grid\Helper\ColumnsIterator;
+use APY\DataGridBundle\Grid\Row;
+use APY\DataGridBundle\Grid\Rows;
+use Doctrine\ODM\MongoDB\Query\Builder as QueryBuilder;
+use MongoDB\BSON\Regex;
class Document extends Source
{
@@ -31,7 +34,7 @@ class Document extends Source
protected $manager;
/**
- * e.g. Base\Cms\Document\Page
+ * e.g. Base\Cms\Document\Page.
*/
protected $class;
@@ -41,7 +44,7 @@ class Document extends Source
protected $odmMetadata;
/**
- * e.g. Cms:Page
+ * e.g. Cms:Page.
*/
protected $documentName;
@@ -60,6 +63,16 @@ class Document extends Source
*/
protected $group;
+ /**
+ * @var array
+ */
+ protected $referencedColumns = [];
+
+ /**
+ * @var array
+ */
+ protected $referencedMappings = [];
+
/**
* @param string $documentName e.g. "Cms:Page"
*/
@@ -73,7 +86,7 @@ public function initialise($container)
{
$this->manager = $container->get('doctrine.odm.mongodb.document_manager');
$this->odmMetadata = $this->manager->getClassMetadata($this->documentName);
- $this->class = $this->odmMetadata->getReflectionClass()->name;
+ $this->class = $this->odmMetadata->getReflectionClass()->getName();
$mapping = $container->get('grid.mapping.manager');
$mapping->addDriver($this, -1);
@@ -82,7 +95,6 @@ public function initialise($container)
/**
* @param \APY\DataGridBundle\Grid\Columns $columns
- * @return null
*/
public function getColumns($columns)
{
@@ -117,26 +129,22 @@ protected function normalizeOperator($operator)
protected function normalizeValue($operator, $value)
{
switch ($operator) {
- case Column::OPERATOR_EQ:
- return new \MongoRegex('/^'.$value.'$/i');
case Column::OPERATOR_NEQ:
- return new \MongoRegex('/^(?!'.$value.'$).*$/i');
+ return new Regex('^(?!' . $value . '$).*$', 'i');
case Column::OPERATOR_LIKE:
- return new \MongoRegex('/'.$value.'/i');
+ return new Regex($value, 'i');
case Column::OPERATOR_NLIKE:
- return new \MongoRegex('/^((?!'.$value.').)*$/i');
+ return new Regex('^((?!' . $value . ').)*$', 'i');
case Column::OPERATOR_RLIKE:
- return new \MongoRegex('/^'.$value.'/i');
+ return new Regex('^' . $value, 'i');
case Column::OPERATOR_LLIKE:
- return new \MongoRegex('/'.$value.'$/i');
- case Column::OPERATOR_SLIKE:
- return new \MongoRegex('/'.$value.'/');
+ return new Regex($value . '$', 'i');
case Column::OPERATOR_SLIKE:
- return new \MongoRegex('/^((?!'.$value.').)*$/');
+ return new Regex($value, '');
case Column::OPERATOR_RSLIKE:
- return new \MongoRegex('/^'.$value.'/');
+ return new Regex('^' . $value, '');
case Column::OPERATOR_LSLIKE:
- return new \MongoRegex('/'.$value.'$/');
+ return new Regex($value . '$', '');
case Column::OPERATOR_ISNULL:
return false;
case Column::OPERATOR_ISNOTNULL:
@@ -147,17 +155,54 @@ protected function normalizeValue($operator, $value)
}
/**
- * @param \APY\DataGridBundle\Grid\Column\Column[] $columns
- * @param int $page Page Number
- * @param int $limit Rows Per Page
- * @param int $gridDataJunction Grid data junction
+ * Sets the initial QueryBuilder for this DataGrid.
+ *
+ * @param QueryBuilder $queryBuilder
+ */
+ public function initQueryBuilder(QueryBuilder $queryBuilder)
+ {
+ $this->query = clone $queryBuilder;
+ }
+
+ /**
+ * @return QueryBuilder
+ */
+ protected function getQueryBuilder()
+ {
+ //If a custom QB has been provided, use that
+ //Otherwise create our own basic one
+ if ($this->query instanceof QueryBuilder) {
+ $qb = $this->query;
+ } else {
+ $qb = $this->query = $this->manager->createQueryBuilder($this->documentName);
+ }
+
+ return $qb;
+ }
+
+ /**
+ * @param ColumnsIterator $columns
+ * @param int $page Page Number
+ * @param int $limit Rows Per Page
+ * @param int $gridDataJunction Grid data junction
+ *
* @return \APY\DataGridBundle\Grid\Rows
*/
public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gridDataJunction = Column::DATA_CONJUNCTION)
{
- $this->query = $this->manager->createQueryBuilder($this->documentName);
+ $this->query = $this->getQueryBuilder();
+ $validColumns = [];
foreach ($columns as $column) {
+
+ //checks if exists '.' notation on referenced columns and build query if it's filtered
+ $subColumn = explode('.', $column->getId());
+ if (count($subColumn) > 1 && isset($this->referencedMappings[$subColumn[0]])) {
+ $this->addReferencedColumnn($subColumn, $column);
+
+ continue;
+ }
+
$this->query->select($column->getField());
if ($column->isSorted()) {
@@ -180,9 +225,10 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
} else {
$this->query->field($column->getField())->$operator($value);
}
-
}
}
+
+ $validColumns[] = $column;
}
if ($page > 0) {
@@ -205,6 +251,8 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
//execute and get results
$result = new Rows();
+ // I really don't know if Cursor is the right type returned (I mean, every single type).
+ // As I didn't find out this information, I'm gonna test it with Cursor returned only.
$cursor = $this->query->getQuery()->execute();
$this->count = $cursor->count();
@@ -213,14 +261,16 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
$row = new Row();
$properties = $this->getClassProperties($resource);
- foreach ($columns as $column) {
- if (isset($properties[$column->getId()])) {
- $row->setField($column->getId(), $properties[$column->getId()]);
+ foreach ($validColumns as $column) {
+ if (isset($properties[strtolower($column->getId())])) {
+ $row->setField($column->getId(), $properties[strtolower($column->getId())]);
}
}
+ $this->addReferencedFields($row, $resource);
+
//call overridden prepareRow or associated closure
- if (($modifiedRow = $this->prepareRow($row)) != null) {
+ if (($modifiedRow = $this->prepareRow($row)) !== null) {
$result->addRow($modifiedRow);
}
}
@@ -228,10 +278,75 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
return $result;
}
+ /**
+ * @param array $subColumn
+ * @param Column \APY\DataGridBundle\Grid\Column\Column
+ */
+ protected function addReferencedColumnn(array $subColumn, Column $column)
+ {
+ $this->referencedColumns[$subColumn[0]][] = $subColumn[1];
+
+ if ($column->isFiltered()) {
+ $helperQuery = $this->manager->createQueryBuilder($this->referencedMappings[$subColumn[0]]);
+ $filters = $column->getFilters('document');
+ foreach ($filters as $filter) {
+ $operator = $this->normalizeOperator($filter->getOperator());
+ $value = $this->normalizeValue($filter->getOperator(), $filter->getValue());
+
+ $helperQuery->field($subColumn[1])->$operator($value);
+ $this->prepareQuery($this->query);
+
+ $cursor = $helperQuery->getQuery()->execute();
+
+ foreach ($cursor as $resource) {
+ // Is this case possible? I don't think so
+ if ($cursor->count() > 0) {
+ $this->query->select($subColumn[0]);
+ }
+
+ if ($cursor->count() == 1) {
+ $this->query->field($subColumn[0])->references($resource);
+ } else {
+ $this->query->addOr($this->query->expr()->field($subColumn[0])->references($resource));
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * @param \APY\DataGridBundle\Grid\Row $row
+ * @param Document $resource
+ *
+ * @throws \Exception if getter for field does not exists
+ *
+ * @return \APY\DataGridBundle\Grid\Row $row with referenced fields
+ */
+ protected function addReferencedFields(Row $row, $resource)
+ {
+ foreach ($this->referencedColumns as $parent => $subColumns) {
+ $node = $this->getClassProperties($resource);
+ if (isset($node[strtolower($parent)])) {
+ $node = $node[strtolower($parent)];
+
+ foreach ($subColumns as $field) {
+ $getter = 'get' . ucfirst($field);
+ if (method_exists($node, $getter)) {
+ $row->setField($parent . '.' . $field, $node->$getter());
+ } else {
+ throw new \Exception(sprintf('Method %s for Document %s not exists', $getter, $this->referencedMappings[$parent]));
+ }
+ }
+ }
+ }
+
+ return $row;
+ }
+
public function getTotalCount($maxResults = null)
{
if ($maxResults !== null) {
- return min(array($maxResults, $this->count));
+ return min([$maxResults, $this->count]);
}
return $this->count;
@@ -240,24 +355,30 @@ public function getTotalCount($maxResults = null)
protected function getClassProperties($obj)
{
$reflect = new \ReflectionClass($obj);
- $props = $reflect->getProperties();
- $result = array();
+ $props = $reflect->getProperties();
+ $result = [];
foreach ($props as $property) {
$property->setAccessible(true);
- $result[$property->getName()] = $property->getValue($obj);
+ $result[strtolower($property->getName())] = $property->getValue($obj);
}
return $result;
}
+ /**
+ * @param string $class
+ * @param string $group
+ *
+ * @return array
+ */
public function getFieldsMetadata($class, $group = 'default')
{
- $result = array();
+ $result = [];
foreach ($this->odmMetadata->getReflectionProperties() as $property) {
$name = $property->getName();
$mapping = $this->odmMetadata->getFieldMapping($name);
- $values = array('title' => $name, 'source' => true);
+ $values = ['title' => $name, 'source' => true];
if (isset($mapping['fieldName'])) {
$values['field'] = $mapping['fieldName'];
@@ -286,7 +407,7 @@ public function getFieldsMetadata($class, $group = 'default')
$values['type'] = 'number';
break;
/*case 'hash':
- $values['type'] = 'array';*/
+ $values['type'] = 'array';*/
case 'boolean':
$values['type'] = 'boolean';
break;
@@ -299,6 +420,9 @@ public function getFieldsMetadata($class, $group = 'default')
break;
case 'one':
$values['type'] = 'array';
+ if (isset($mapping['reference']) && $mapping['reference'] === true) {
+ $this->referencedMappings[$name] = $mapping['targetDocument'];
+ }
break;
case 'many':
$values['type'] = 'array';
@@ -315,7 +439,7 @@ public function getFieldsMetadata($class, $group = 'default')
public function populateSelectFilters($columns, $loop = false)
{
- $queryFromSource = $this->manager->createQueryBuilder($this->documentName);
+ $queryFromSource = $this->getQueryBuilder();
$queryFromQuery = clone $this->query;
// Clean the select fields from the query
@@ -332,7 +456,7 @@ public function populateSelectFilters($columns, $loop = false)
// For negative operators, show all values
if ($selectFrom === 'query') {
foreach ($column->getFilters('document') as $filter) {
- if (in_array($filter->getOperator(), array(Column::OPERATOR_NEQ, Column::OPERATOR_NLIKE,Column::OPERATOR_NSLIKE))) {
+ if (in_array($filter->getOperator(), [Column::OPERATOR_NEQ, Column::OPERATOR_NLIKE, Column::OPERATOR_NSLIKE])) {
$selectFrom = 'source';
break;
}
@@ -350,9 +474,8 @@ public function populateSelectFilters($columns, $loop = false)
->getQuery()
->execute();
- $values = array();
+ $values = [];
foreach ($result as $value) {
-
switch ($column->getType()) {
case 'number':
$values[$value] = $column->getDisplayedValue($value);
@@ -365,7 +488,7 @@ public function populateSelectFilters($columns, $loop = false)
}
// Mongodb bug ? timestamp value is on the key 'i' instead of the key 't'
- if (is_array($value) && array_keys($value) == array('t','i')) {
+ if (is_array($value) && array_keys($value) == ['t', 'i']) {
$value = $value['i'];
}
@@ -382,12 +505,18 @@ public function populateSelectFilters($columns, $loop = false)
$column->setSelectFrom('source');
$this->populateSelectFilters($columns, true);
} else {
+ $values = $this->prepareColumnValues($column, $values);
$column->setValues($values);
}
}
}
}
+ /**
+ * @param array $ids
+ *
+ * @throws \Exception
+ */
public function delete(array $ids)
{
$repository = $this->getRepository();
@@ -405,13 +534,39 @@ public function delete(array $ids)
$this->manager->flush();
}
+ /**
+ * @return \Doctrine\ODM\MongoDB\DocumentRepository
+ */
public function getRepository()
{
- return$this->manager->getRepository($this->documentName);
+ return $this->manager->getRepository($this->documentName);
}
+ /**
+ * @return string
+ */
public function getHash()
{
return $this->documentName;
}
+
+ /**
+ * Get the value of query
+ *
+ * @return \Doctrine\ODM\MongoDB\Query\Builder;
+ */
+ public function getQuery()
+ {
+ return $this->query;
+ }
+
+ /**
+ * Get the value of referencedMappings
+ *
+ * @return array
+ */
+ public function getReferencedMappings()
+ {
+ return $this->referencedMappings;
+ }
}
diff --git a/Grid/Source/Entity.php b/Grid/Source/Entity.php
index ec1ad141..3a006e65 100644
--- a/Grid/Source/Entity.php
+++ b/Grid/Source/Entity.php
@@ -5,6 +5,7 @@
*
* (c) Abhoryo
* (c) Stanislav Turza
+ * (c) Patryk Grudniewski
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
@@ -13,17 +14,26 @@
namespace APY\DataGridBundle\Grid\Source;
use APY\DataGridBundle\Grid\Column\Column;
-use APY\DataGridBundle\Grid\Rows;
+use APY\DataGridBundle\Grid\Column\JoinColumn;
use APY\DataGridBundle\Grid\Row;
+use APY\DataGridBundle\Grid\Rows;
+use Doctrine\ORM\Internal\SQLResultCasing;
use Doctrine\ORM\NoResultException;
use Doctrine\ORM\Query;
use Doctrine\ORM\QueryBuilder;
-use Symfony\Component\HttpKernel\Kernel;
+use Doctrine\ORM\Query\Expr\Join;
use Doctrine\ORM\Query\ResultSetMapping;
use Doctrine\ORM\Tools\Pagination\CountWalker;
+use Doctrine\ORM\Tools\Pagination\Paginator;
+use Symfony\Component\HttpKernel\Kernel;
class Entity extends Source
{
+ use SQLResultCasing;
+
+ const DOT_DQL_ALIAS_PH = '__dot__';
+ const COLON_DQL_ALIAS_PH = '__col__';
+
/**
* @var \Doctrine\ORM\EntityManager
*/
@@ -54,7 +64,6 @@ class Entity extends Source
*/
protected $managerName;
-
/**
* @var \APY\DataGridBundle\Grid\Mapping\Metadata\Metadata
*/
@@ -90,36 +99,43 @@ class Entity extends Source
* You can override this if the querybuilder is constructed in a business-specific way
* by an external controller/service/repository and you wish to re-use it for the datagrid.
* Typical use-case involves an external repository creating complex default restriction (i.e. multi-tenancy etc)
- * which then will be expanded on by the datagrid
+ * which then will be expanded on by the datagrid.
+ *
* @var QueryBuilder
*/
protected $queryBuilder;
-
/**
- * The table alias that will be used in the query to fetch actual data
+ * The table alias that will be used in the query to fetch actual data.
+ *
* @var string
*/
protected $tableAlias;
+ /**
+ * @var null
+ */
+ protected $prepareCountQueryCallback = null;
+
/**
* Legacy way of accessing the default alias (before it became possible to change it)
- * Please use $entity->getTableAlias() now instead of $entity::TABLE_ALIAS
+ * Please use $entity->getTableAlias() now instead of $entity::TABLE_ALIAS.
+ *
* @deprecated
*/
const TABLE_ALIAS = '_a';
/**
- * @param string $entityName e.g Cms:Page
+ * @param string $entityName e.g Cms:Page
* @param string $managerName e.g. mydatabase
*/
public function __construct($entityName, $group = 'default', $managerName = null)
{
$this->entityName = $entityName;
$this->managerName = $managerName;
- $this->joins = array();
+ $this->joins = [];
$this->group = $group;
- $this->hints = array();
+ $this->hints = [];
$this->setTableAlias(self::TABLE_ALIAS);
}
@@ -134,13 +150,49 @@ public function initialise($container)
$mapping = $container->get('grid.mapping.manager');
- /** todo autoregister mapping drivers with tag */
+ /* todo autoregister mapping drivers with tag */
$mapping->addDriver($this, -1);
$this->metadata = $mapping->getMetadata($this->class, $this->group);
$this->groupBy = $this->metadata->getGroupBy();
}
+ /**
+ * @param \APY\DataGridBundle\Grid\Column\Column $column
+ *
+ * @return string
+ */
+ protected function getTranslationFieldNameWithParents($column)
+ {
+ $name = $column->getField();
+
+ if ($column->getIsManualField()) {
+ return $column->getField();
+ }
+
+ if (strpos($name, '.') !== false) {
+ $previousParent = '';
+
+ $elements = explode('.', $name);
+ while ($element = array_shift($elements)) {
+ if (count($elements) > 0) {
+ $previousParent .= '_' . $element;
+ }
+ }
+ } elseif (strpos($name, ':') !== false) {
+ $previousParent = $this->getTableAlias();
+ } else {
+ return $this->getTableAlias().'.'.$name;
+ }
+
+ $matches = array();
+ if ($column->hasDQLFunction($matches)) {
+ return $previousParent.'.'.$matches['field'];
+ }
+
+ return $column->getField();
+ }
+
/**
* @param \APY\DataGridBundle\Grid\Column\Column $column
* @return string
@@ -149,7 +201,7 @@ protected function getFieldName($column, $withAlias = false)
{
$name = $column->getField();
- if($column->getIsManualField()) {
+ if ($column->getIsManualField()) {
return $column->getField();
}
@@ -161,32 +213,32 @@ protected function getFieldName($column, $withAlias = false)
if (count($elements) > 0) {
$parent = ($previousParent == '') ? $this->getTableAlias() : $previousParent;
$previousParent .= '_' . $element;
- $this->joins[$previousParent] = array('field' => $parent . '.' . $element, 'type' => $column->getJoinType());
+ $this->joins[$previousParent] = ['field' => $parent . '.' . $element, 'type' => $column->getJoinType()];
} else {
$name = $previousParent . '.' . $element;
}
}
- $alias = str_replace('.', '::', $column->getId());
+ $alias = $this->fromColIdToAlias($column->getId());
} elseif (strpos($name, ':') !== false) {
$previousParent = $this->getTableAlias();
$alias = $name;
} else {
- return $this->getTableAlias().'.'.$name;
+ return $this->getTableAlias() . '.' . $name;
}
// Aggregate dql functions
- $matches = array();
+ $matches = [];
if ($column->hasDQLFunction($matches)) {
if (strtolower($matches['parameters']) == 'distinct') {
- $functionWithParameters = $matches['function'].'(DISTINCT '.$previousParent.'.'.$matches['field'].')';
+ $functionWithParameters = $matches['function'] . '(DISTINCT ' . $previousParent . '.' . $matches['field'] . ')';
} else {
$parameters = '';
if ($matches['parameters'] !== '') {
- $parameters = ', ' . (is_numeric($matches['parameters']) ? $matches['parameters'] : "'".$matches['parameters']."'");
+ $parameters = ', ' . (is_numeric($matches['parameters']) ? $matches['parameters'] : "'" . $matches['parameters'] . "'");
}
- $functionWithParameters = $matches['function'].'('.$previousParent.'.'.$matches['field'].$parameters.')';
+ $functionWithParameters = $matches['function'] . '(' . $previousParent . '.' . $matches['field'] . $parameters . ')';
}
if ($withAlias) {
@@ -207,8 +259,19 @@ protected function getFieldName($column, $withAlias = false)
return $name;
}
+ /**
+ * @param string $colId
+ *
+ * @return string
+ */
+ private function fromColIdToAlias($colId)
+ {
+ return str_replace(['.', ':'], [self::DOT_DQL_ALIAS_PH, self::COLON_DQL_ALIAS_PH], $colId);
+ }
+
/**
* @param string $fieldName
+ *
* @return string
*/
protected function getGroupByFieldName($fieldName)
@@ -229,7 +292,7 @@ protected function getGroupByFieldName($fieldName)
$fieldName = substr($fieldName, 0, $pos);
}
- return $this->getTableAlias().'.'.$fieldName;
+ return $this->getTableAlias() . '.' . $fieldName;
}
return $name;
@@ -237,7 +300,6 @@ protected function getGroupByFieldName($fieldName)
/**
* @param \APY\DataGridBundle\Grid\Columns $columns
- * @return null
*/
public function getColumns($columns)
{
@@ -258,7 +320,7 @@ protected function normalizeOperator($operator)
case Column::OPERATOR_LSLIKE:
case Column::OPERATOR_RSLIKE:
case Column::OPERATOR_NSLIKE:
- return 'like';
+ return 'like';
default:
return $operator;
}
@@ -285,14 +347,16 @@ protected function normalizeValue($operator, $value)
}
/**
- * Sets the initial QueryBuilder for this DataGrid
+ * Sets the initial QueryBuilder for this DataGrid.
+ *
* @param QueryBuilder $queryBuilder
*/
public function initQueryBuilder(QueryBuilder $queryBuilder)
{
$this->queryBuilder = clone $queryBuilder;
- //Try to guess the new root alias and apply it to our queries+ //as the external querybuilder almost certainly is not used our default alias
+ //Try to guess the new root alias and apply it to our queries+
+ //as the external querybuilder almost certainly is not used our default alias
$externalTableAliases = $this->queryBuilder->getRootAliases();
if (count($externalTableAliases)) {
$this->setTableAlias($externalTableAliases[0]);
@@ -304,10 +368,10 @@ public function initQueryBuilder(QueryBuilder $queryBuilder)
*/
protected function getQueryBuilder()
{
- //If a custom QB has been provided, use that
+ //If a custom QB has been provided, use a copy of that one
//Otherwise create our own basic one
if ($this->queryBuilder instanceof QueryBuilder) {
- $qb = $this->queryBuilder;
+ $qb = clone $this->queryBuilder;
} else {
$qb = $this->manager->createQueryBuilder($this->class);
$qb->from($this->class, $this->getTableAlias());
@@ -318,9 +382,10 @@ protected function getQueryBuilder()
/**
* @param \APY\DataGridBundle\Grid\Column\Column[] $columns
- * @param int $page Page Number
- * @param int $limit Rows Per Page
- * @param int $gridDataJunction Grid data junction
+ * @param int $page Page Number
+ * @param int $limit Rows Per Page
+ * @param int $gridDataJunction Grid data junction
+ *
* @return \APY\DataGridBundle\Grid\Rows
*/
public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gridDataJunction = Column::DATA_CONJUNCTION)
@@ -329,26 +394,26 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
$this->querySelectfromSource = clone $this->query;
$bindIndex = 123;
- $serializeColumns = array();
+ $serializeColumns = [];
$where = $gridDataJunction === Column::DATA_CONJUNCTION ? $this->query->expr()->andx() : $this->query->expr()->orx();
- $columnsById = array();
+ $columnsById = [];
foreach ($columns as $column) {
$columnsById[$column->getId()] = $column;
}
foreach ($columns as $column) {
-
// If a column is a manual field, ie a.col*b.col as myfield, it is added to select from user.
- if($column->getIsManualField() === false) {
+ if ($column->getIsManualField() === false) {
$fieldName = $this->getFieldName($column, true);
$this->query->addSelect($fieldName);
$this->querySelectfromSource->addSelect($fieldName);
}
if ($column->isSorted()) {
- if ($column->getType() === 'join') {
- foreach($column->getJoinColumns() as $columnName) {
+ if ($column instanceof JoinColumn) {
+ $this->query->resetDQLPart('orderBy');
+ foreach ($column->getJoinColumns() as $columnName) {
$this->query->addOrderBy($this->getFieldName($columnsById[$columnName]), $column->getOrder());
}
} else {
@@ -362,22 +427,35 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
$isDisjunction = $column->getDataJunction() === Column::DATA_DISJUNCTION;
- $hasHavingClause = $column->hasDQLFunction() || $column->getIsAggregate();
+ $dqlMatches = [];
+ $hasHavingClause = $column->hasDQLFunction($dqlMatches) || $column->getIsAggregate();
+ if(isset($dqlMatches['function']) && $dqlMatches['function'] == 'translation_agg'){
+ $hasHavingClause = false;
+ }
$sub = $isDisjunction ? $this->query->expr()->orx() : ($hasHavingClause ? $this->query->expr()->andx() : $where);
foreach ($filters as $filter) {
$operator = $this->normalizeOperator($filter->getOperator());
- $columnForFilter = ($column->getType() !== 'join') ? $column : $columnsById[$filter->getColumnName()];
+ $columnForFilter = (!$column instanceof JoinColumn) ? $column : $columnsById[$filter->getColumnName()];
$fieldName = $this->getFieldName($columnForFilter, false);
$bindIndexPlaceholder = "?$bindIndex";
+
if( in_array($filter->getOperator(), array(Column::OPERATOR_LIKE,Column::OPERATOR_RLIKE,Column::OPERATOR_LLIKE,Column::OPERATOR_NLIKE,))){
- $fieldName = "LOWER($fieldName)";
+ if(isset($dqlMatches['function']) && $dqlMatches['function'] == 'translation_agg'){
+ $translationFieldName = $this->getTranslationFieldNameWithParents($columnForFilter);
+ $fieldName = "LOWER(".$translationFieldName.")";
+ }elseif(isset($dqlMatches['function']) && $dqlMatches['function'] == 'role_agg'){
+ $translationFieldName = $this->getTranslationFieldNameWithParents($columnForFilter);
+ $fieldName = "LOWER(".$translationFieldName.")";
+ }else{
+ $fieldName = "LOWER($fieldName)";
+ }
$bindIndexPlaceholder = "LOWER($bindIndexPlaceholder)";
}
-
+
$q = $this->query->expr()->$operator($fieldName, $bindIndexPlaceholder);
if ($filter->getOperator() == Column::OPERATOR_NLIKE || $filter->getOperator() == Column::OPERATOR_NSLIKE) {
@@ -403,7 +481,7 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
}
}
- if ($where->count()> 0) {
+ if ($where->count() > 0) {
//Using ->andWhere here to make sure we preserve any other where clauses present in the query builder
//the other where clauses may have come from an external builder
$this->query->andWhere($where);
@@ -446,12 +524,14 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
//call overridden prepareQuery or associated closure
$this->prepareQuery($this->query);
+ $hasJoin = $this->checkIfQueryHasFetchJoin($this->query);
$query = $this->query->getQuery();
foreach ($this->hints as $hintKey => $hintValue) {
$query->setHint($hintKey, $hintValue);
}
- $items = $query->getResult();
+ $items = new Paginator($query, $hasJoin);
+ $items->setUseOutputWalkers(false);
$repository = $this->manager->getRepository($this->entityName);
@@ -472,7 +552,7 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
$row = new Row();
foreach ($item as $key => $value) {
- $key = str_replace('::', '.', $key);
+ $key = $this->fromAliasToColId($key);
if (in_array($key, $serializeColumns) && is_string($value)) {
$value = unserialize($value);
@@ -487,7 +567,7 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
$row->setRepository($repository);
//call overridden prepareRow or associated closure
- if (($modifiedRow = $this->prepareRow($row)) != null) {
+ if (($modifiedRow = $this->prepareRow($row)) !== null) {
$result->addRow($modifiedRow);
}
}
@@ -495,10 +575,23 @@ public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gr
return $result;
}
+ /**
+ * @param string $alias
+ *
+ * @return string
+ */
+ private function fromAliasToColId($alias)
+ {
+ return str_replace([self::DOT_DQL_ALIAS_PH, self::COLON_DQL_ALIAS_PH], ['.', ':'], $alias);
+ }
+
public function getTotalCount($maxResults = null)
{
// Doctrine Bug Workaround: http://www.doctrine-project.org/jira/browse/DDC-1927
$countQueryBuilder = clone $this->query;
+
+ $this->prepareCountQuery($countQueryBuilder);
+
foreach ($countQueryBuilder->getRootAliases() as $alias) {
$countQueryBuilder->addSelect($alias);
}
@@ -511,15 +604,15 @@ public function getTotalCount($maxResults = null)
$countQuery->setHint($hintName, $hintValue);
}
- if (! $countQuery->getHint(CountWalker::HINT_DISTINCT)) {
+ if (!$countQuery->getHint(CountWalker::HINT_DISTINCT)) {
$countQuery->setHint(CountWalker::HINT_DISTINCT, true);
}
- if ($countQuery->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) == false) {
+ if ($countQuery->getHint(Query::HINT_CUSTOM_OUTPUT_WALKER) === false) {
$platform = $countQuery->getEntityManager()->getConnection()->getDatabasePlatform(); // law of demeter win
$rsm = new ResultSetMapping();
- $rsm->addScalarResult($platform->getSQLResultCasing('dctrn_count'), 'count');
+ $rsm->addScalarResult($this->getSQLResultCasing($platform,'dctrn_count'), 'count');
$countQuery->setHint(Query::HINT_CUSTOM_OUTPUT_WALKER, 'Doctrine\ORM\Tools\Pagination\CountOutputWalker');
$countQuery->setResultSetMapping($rsm);
@@ -527,14 +620,14 @@ public function getTotalCount($maxResults = null)
$hints = $countQuery->getHint(Query::HINT_CUSTOM_TREE_WALKERS);
if ($hints === false) {
- $hints = array();
+ $hints = [];
}
$hints[] = 'Doctrine\ORM\Tools\Pagination\CountWalker';
//$hints[] = 'APY\DataGridBundle\Grid\Helper\ORMCountWalker';
$countQuery->setHint(Query::HINT_CUSTOM_TREE_WALKERS, $hints);
}
- $countQuery->setFirstResult(null)->setMaxResults($maxResults);
+ $countQuery->setFirstResult(0)->setMaxResults($maxResults);
try {
$data = $countQuery->getScalarResult();
@@ -549,10 +642,10 @@ public function getTotalCount($maxResults = null)
public function getFieldsMetadata($class, $group = 'default')
{
- $result = array();
+ $result = [];
foreach ($this->ormMetadata->getFieldNames() as $name) {
$mapping = $this->ormMetadata->getFieldMapping($name);
- $values = array('title' => $name, 'source' => true);
+ $values = ['title' => $name, 'source' => true];
if (isset($mapping['fieldName'])) {
$values['field'] = $mapping['fieldName'];
@@ -610,7 +703,7 @@ public function populateSelectFilters($columns, $loop = false)
// For negative operators, show all values
if ($selectFrom === 'query') {
foreach ($column->getFilters('entity') as $filter) {
- if (in_array($filter->getOperator(), array(Column::OPERATOR_NEQ, Column::OPERATOR_NLIKE,Column::OPERATOR_NSLIKE))) {
+ if (in_array($filter->getOperator(), [Column::OPERATOR_NEQ, Column::OPERATOR_NLIKE, Column::OPERATOR_NSLIKE])) {
$selectFrom = 'source';
break;
}
@@ -620,17 +713,24 @@ public function populateSelectFilters($columns, $loop = false)
// Dynamic from query or not ?
$query = ($selectFrom === 'source') ? clone $this->querySelectfromSource : clone $this->query;
- $result = $query->select($this->getFieldName($column, true))
+ $query = $query->select($this->getFieldName($column, true))
->distinct()
->orderBy($this->getFieldName($column), 'asc')
->setFirstResult(null)
->setMaxResults(null)
- ->getQuery()
- ->getResult();
+ ->getQuery();
+ if ($selectFrom === 'query') {
+ foreach ($this->hints as $hintKey => $hintValue) {
+ $query->setHint($hintKey, $hintValue);
+ }
+ }
+ $result = $query->getResult();
- $values = array();
+ $values = [];
foreach ($result as $row) {
- $value = $row[str_replace('.', '::', $column->getId())];
+ $alias = $this->fromColIdToAlias($column->getId());
+
+ $value = $row[$alias];
switch ($column->getType()) {
case 'array':
@@ -641,6 +741,14 @@ public function populateSelectFilters($columns, $loop = false)
$values[$val] = $val;
}
break;
+ case 'simple_array':
+ if (is_string($value)) {
+ $value = explode(',', $value);
+ }
+ foreach ($value as $val) {
+ $values[$val] = $val;
+ }
+ break;
case 'number':
$values[$value] = $column->getDisplayedValue($value);
break;
@@ -664,12 +772,35 @@ public function populateSelectFilters($columns, $loop = false)
natcasesort($values);
}
+ $values = $this->prepareColumnValues($column, $values);
$column->setValues($values);
}
}
}
}
+ /**
+ * @param QueryBuilder $countQueryBuilder
+ */
+ public function prepareCountQuery(QueryBuilder $countQueryBuilder)
+ {
+ if (is_callable($this->prepareCountQueryCallback)) {
+ call_user_func($this->prepareCountQueryCallback, $countQueryBuilder);
+ }
+ }
+
+ /**
+ * @param callable $callback
+ *
+ * @return $this
+ */
+ public function manipulateCountQuery($callback = null)
+ {
+ $this->prepareCountQueryCallback = $callback;
+
+ return $this;
+ }
+
public function delete(array $ids)
{
$repository = $this->getRepository();
@@ -704,11 +835,12 @@ public function addHint($key, $value)
public function clearHints()
{
- $this->hints = array();
+ $this->hints = [];
}
/**
- * Set groupby column
+ * Set groupby column.
+ *
* @param string $groupBy GroupBy column
*/
public function setGroupBy($groupBy)
@@ -736,5 +868,24 @@ public function getTableAlias()
{
return $this->tableAlias;
}
-
+
+ /**
+ * @param QueryBuilder $qb
+ * @return boolean
+ */
+ protected function checkIfQueryHasFetchJoin(QueryBuilder $qb)
+ {
+ $join = $qb->getDqlPart('join');
+ if (empty($join)) {
+ return false;
+ }
+
+ foreach ($join[$this->getTableAlias()] as $join) {
+ if ($join->getJoinType() === Join::INNER_JOIN || $join->getJoinType() === Join::LEFT_JOIN) {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/Grid/Source/Source.php b/Grid/Source/Source.php
old mode 100755
new mode 100644
index 56921bbb..8d685548
--- a/Grid/Source/Source.php
+++ b/Grid/Source/Source.php
@@ -12,18 +12,19 @@
namespace APY\DataGridBundle\Grid\Source;
+use APY\DataGridBundle\Grid\Column\Column;
+use APY\DataGridBundle\Grid\Exception\PropertyAccessDeniedException;
+use APY\DataGridBundle\Grid\Helper\ColumnsIterator;
use APY\DataGridBundle\Grid\Mapping\Driver\DriverInterface;
-use Symfony\Component\Form\Exception\PropertyAccessDeniedException;
-use APY\DataGridBundle\Grid\Column;
-use APY\DataGridBundle\Grid\Rows;
use APY\DataGridBundle\Grid\Row;
+use APY\DataGridBundle\Grid\Rows;
abstract class Source implements DriverInterface
{
protected $prepareQueryCallback = null;
protected $prepareRowCallback = null;
protected $data = null;
- protected $items = array();
+ protected $items = [];
protected $count;
/**
@@ -38,6 +39,7 @@ public function prepareQuery($queryBuilder)
/**
* @param \APY\DataGridBundle\Grid\Row $row
+ *
* @return \APY\DataGridBundle\Grid\Row|null
*/
public function prepareRow($row)
@@ -51,6 +53,7 @@ public function prepareRow($row)
/**
* @param callable $callback
+ *
* @return $this
*/
public function manipulateQuery($callback = null)
@@ -71,77 +74,82 @@ public function manipulateRow(\Closure $callback = null)
}
/**
- * Find data for current page
+ * Find data for current page.
*
* @abstract
- * @param \APY\DataGridBundle\Grid\Column\Column[] $columns
- * @param int $page Page Number
- * @param int $limit Rows Per Page
- * @param int $gridDataJunction Grid data junction
+ *
+ * @param ColumnsIterator $columns
+ * @param int $page Page Number
+ * @param int $limit Rows Per Page
+ * @param int $gridDataJunction Grid data junction
+ *
* @return \APY\DataGridBundle\Grid\Rows
*/
+ // @todo: typehint?
abstract public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gridDataJunction = Column::DATA_CONJUNCTION);
/**
- * Get Total count of data items
+ * Get Total count of data items.
*
* @param int $maxResults
+ *
* @return int
*/
abstract public function getTotalCount($maxResults = null);
/**
- * Set container
+ * Set container.
*
* @abstract
+ *
* @param $container
- * @return void
*/
abstract public function initialise($container);
/**
* @abstract
+ *
* @param $columns
*/
abstract public function getColumns($columns);
public function getClassColumns($class, $group = 'default')
{
- return array();
+ return [];
}
public function getFieldsMetadata($class, $group = 'default')
{
- return array();
+ return [];
}
public function getGroupBy($class, $group = 'default')
{
- return array();
+ return [];
}
abstract public function populateSelectFilters($columns, $loop = false);
/**
- * Return source hash string
- * @abstract
- */
+ * Return source hash string.
+ *
+ * @abstract
+ */
abstract public function getHash();
/**
- * Delete one or more objects
+ * Delete one or more objects.
*
* @abstract
+ *
* @param array $ids
- * @return void
*/
abstract public function delete(array $ids);
/**
- * Use data instead of fetching the source
+ * Use data instead of fetching the source.
*
* @param array|object $data
- * @return void
*/
public function setData($data)
{
@@ -151,7 +159,7 @@ public function setData($data)
}
/**
- * Get the loaded data
+ * Get the loaded data.
*
* @return array|object
*/
@@ -161,9 +169,9 @@ public function getData()
}
/**
- * Check if data is loaded
+ * Check if data is loaded.
*
- * @return boolean
+ * @return bool
*/
public function isDataLoaded()
{
@@ -171,13 +179,13 @@ public function isDataLoaded()
}
/**
- * Gets an array of data items for rows from the set data
+ * Gets an array of data items for rows from the set data.
*
* @return array
*/
protected function getItemsFromData($columns)
{
- $items = array();
+ $items = [];
foreach ($this->data as $key => $item) {
foreach ($columns as $column) {
@@ -194,7 +202,7 @@ protected function getItemsFromData($columns)
$elements = explode('.', $fieldName);
while ($element = array_shift($elements)) {
if (count($elements) > 0) {
- $itemEntity = call_user_func(array($itemEntity, 'get'.$element));
+ $itemEntity = call_user_func([$itemEntity, 'get' . $element]);
} else {
$functionName = ucfirst($element);
}
@@ -204,10 +212,10 @@ protected function getItemsFromData($columns)
// Get value of the column
if (isset($itemEntity->$fieldName)) {
$fieldValue = $itemEntity->$fieldName;
- } elseif (is_callable(array($itemEntity, $fullFunctionName = 'get'.$functionName))
- || is_callable(array($itemEntity, $fullFunctionName = 'has'.$functionName))
- || is_callable(array($itemEntity, $fullFunctionName = 'is'.$functionName))) {
- $fieldValue = call_user_func(array($itemEntity, $fullFunctionName));
+ } elseif (is_callable([$itemEntity, $fullFunctionName = 'get' . $functionName])
+ || is_callable([$itemEntity, $fullFunctionName = 'has' . $functionName])
+ || is_callable([$itemEntity, $fullFunctionName = 'is' . $functionName])) {
+ $fieldValue = call_user_func([$itemEntity, $fullFunctionName]);
} else {
throw new PropertyAccessDeniedException(sprintf('Property "%s" is not public or has no accessor.', $fieldName));
}
@@ -223,21 +231,22 @@ protected function getItemsFromData($columns)
}
/**
- * Find data from array|object
+ * Find data from array|object.
+ *
+ * @param Column[] $columns
+ * @param int $page
+ * @param int $limit
+ * @param int $maxResults
*
- * @param \APY\DataGridBundle\Grid\Column\Column[] $columns
- * @param int $page
- * @param int $limit
- * @return \APY\DataGridBundle\DataGrid\Rows
+ * @return Rows
*/
public function executeFromData($columns, $page = 0, $limit = 0, $maxResults = null)
{
// Populate from data
$items = $this->getItemsFromData($columns);
- $serializeColumns = array();
+ $serializeColumns = [];
foreach ($this->data as $key => $item) {
- $keep = true;
foreach ($columns as $column) {
$fieldName = $column->getField();
@@ -253,7 +262,7 @@ public function executeFromData($columns, $page = 0, $limit = 0, $maxResults = n
// Some attributes of the column can be changed in this function
$filters = $column->getFilters('vector');
- if ($column->getDataJunction() === Column\Column::DATA_DISJUNCTION) {
+ if ($column->getDataJunction() === Column::DATA_DISJUNCTION) {
$disjunction = true;
$keep = false;
} else {
@@ -270,79 +279,79 @@ public function executeFromData($columns, $page = 0, $limit = 0, $maxResults = n
if (!$dataIsNumeric && !($value instanceof \DateTime)) {
$value = $this->prepareStringForLikeCompare($value);
switch ($operator) {
- case Column\Column::OPERATOR_EQ:
- $value = '/^'.preg_quote($value, '/').'$/i';
+ case Column::OPERATOR_EQ:
+ $value = '/^' . preg_quote($value, '/') . '$/i';
break;
- case Column\Column::OPERATOR_NEQ:
- $value = '/^(?!'.preg_quote($value, '/').'$).*$/i';
+ case Column::OPERATOR_NEQ:
+ $value = '/^(?!' . preg_quote($value, '/') . '$).*$/i';
break;
- case Column\Column::OPERATOR_LIKE:
- $value = '/'.preg_quote($value, '/').'/i';
+ case Column::OPERATOR_LIKE:
+ $value = '/' . preg_quote($value, '/') . '/i';
break;
- case Column\Column::OPERATOR_NLIKE:
- $value = '/^((?!'.preg_quote($value, '/').').)*$/i';
+ case Column::OPERATOR_NLIKE:
+ $value = '/^((?!' . preg_quote($value, '/') . ').)*$/i';
break;
- case Column\Column::OPERATOR_LLIKE:
- $value = '/'.preg_quote($value, '/').'$/i';
+ case Column::OPERATOR_LLIKE:
+ $value = '/' . preg_quote($value, '/') . '$/i';
break;
- case Column\Column::OPERATOR_RLIKE:
- $value = '/^'.preg_quote($value, '/').'/i';
+ case Column::OPERATOR_RLIKE:
+ $value = '/^' . preg_quote($value, '/') . '/i';
break;
- case Column\Column::OPERATOR_SLIKE:
- $value = '/'.preg_quote($value, '/').'/';
+ case Column::OPERATOR_SLIKE:
+ $value = '/' . preg_quote($value, '/') . '/';
break;
- case Column\Column::OPERATOR_NSLIKE:
- $value = '/^((?!'.preg_quote($value, '/').').)*$/';
+ case Column::OPERATOR_NSLIKE:
+ $value = '/^((?!' . preg_quote($value, '/') . ').)*$/';
break;
- case Column\Column::OPERATOR_LSLIKE:
- $value = '/'.preg_quote($value, '/').'$/';
+ case Column::OPERATOR_LSLIKE:
+ $value = '/' . preg_quote($value, '/') . '$/';
break;
- case Column\Column::OPERATOR_RSLIKE:
- $value = '/^'.preg_quote($value, '/').'/';
+ case Column::OPERATOR_RSLIKE:
+ $value = '/^' . preg_quote($value, '/') . '/';
break;
}
}
// Test
switch ($operator) {
- case Column\Column::OPERATOR_EQ:
+ case Column::OPERATOR_EQ:
if ($dataIsNumeric) {
- $found = abs($fieldValue-$value) < 0.00001;
+ $found = abs($fieldValue - $value) < 0.00001;
break;
}
- case Column\Column::OPERATOR_NEQ:
+ case Column::OPERATOR_NEQ:
if ($dataIsNumeric) {
- $found = abs($fieldValue-$value) > 0.00001;
+ $found = abs($fieldValue - $value) > 0.00001;
break;
}
- case Column\Column::OPERATOR_LIKE:
- case Column\Column::OPERATOR_NLIKE:
- case Column\Column::OPERATOR_LLIKE:
- case Column\Column::OPERATOR_RLIKE:
- case Column\Column::OPERATOR_SLIKE:
- case Column\Column::OPERATOR_NSLIKE:
- case Column\Column::OPERATOR_LSLIKE:
- case Column\Column::OPERATOR_RSLIKE:
+ case Column::OPERATOR_LIKE:
+ case Column::OPERATOR_NLIKE:
+ case Column::OPERATOR_LLIKE:
+ case Column::OPERATOR_RLIKE:
+ case Column::OPERATOR_SLIKE:
+ case Column::OPERATOR_NSLIKE:
+ case Column::OPERATOR_LSLIKE:
+ case Column::OPERATOR_RSLIKE:
$fieldValue = $this->prepareStringForLikeCompare($fieldValue, $column->getType());
$found = preg_match($value, $fieldValue);
break;
- case Column\Column::OPERATOR_GT:
+ case Column::OPERATOR_GT:
$found = $fieldValue > $value;
break;
- case Column\Column::OPERATOR_GTE:
+ case Column::OPERATOR_GTE:
$found = $fieldValue >= $value;
break;
- case Column\Column::OPERATOR_LT:
+ case Column::OPERATOR_LT:
$found = $fieldValue < $value;
break;
- case Column\Column::OPERATOR_LTE:
+ case Column::OPERATOR_LTE:
$found = $fieldValue <= $value;
break;
- case Column\Column::OPERATOR_ISNULL:
+ case Column::OPERATOR_ISNULL:
$found = $fieldValue === null;
break;
- case Column\Column::OPERATOR_ISNOTNULL:
+ case Column::OPERATOR_ISNOTNULL:
$found = $fieldValue !== null;
break;
}
@@ -372,7 +381,7 @@ public function executeFromData($columns, $page = 0, $limit = 0, $maxResults = n
foreach ($columns as $column) {
if ($column->isSorted()) {
$sortType = SORT_REGULAR;
- $sortedItems = array();
+ $sortedItems = [];
foreach ($items as $key => $item) {
$value = $item[$column->getField()];
@@ -434,7 +443,7 @@ public function executeFromData($columns, $page = 0, $limit = 0, $maxResults = n
$row = new Row();
if ($this instanceof Vector) {
- $row->setPrimaryField($this->id);
+ $row->setPrimaryField($this->getId());
}
foreach ($item as $fieldName => $fieldValue) {
@@ -471,7 +480,7 @@ public function populateSelectFiltersFromData($columns, $loop = false)
// For negative operators, show all values
if ($selectFrom === 'query') {
foreach ($column->getFilters('vector') as $filter) {
- if (in_array($filter->getOperator(), array(Column\Column::OPERATOR_NEQ, Column\Column::OPERATOR_NLIKE,Column\Column::OPERATOR_NSLIKE))) {
+ if (in_array($filter->getOperator(), [Column::OPERATOR_NEQ, Column::OPERATOR_NLIKE, Column::OPERATOR_NSLIKE])) {
$selectFrom = 'source';
break;
}
@@ -481,7 +490,7 @@ public function populateSelectFiltersFromData($columns, $loop = false)
// Dynamic from query or not ?
$item = ($selectFrom === 'source') ? $this->data : $this->items;
- $values = array();
+ $values = [];
foreach ($item as $row) {
$value = $row[$column->getField()];
@@ -498,7 +507,7 @@ public function populateSelectFiltersFromData($columns, $loop = false)
}
// Mongodb bug ? timestamp value is on the key 'i' instead of the key 't'
- if (is_array($value) && array_keys($value) == array('t','i')) {
+ if (is_array($value) && array_keys($value) == ['t', 'i']) {
$value = $value['i'];
}
@@ -528,6 +537,7 @@ public function populateSelectFiltersFromData($columns, $loop = false)
natcasesort($values);
}
+ $values = $this->prepareColumnValues($column, $values);
$column->setValues(array_unique($values));
}
}
@@ -535,7 +545,7 @@ public function populateSelectFiltersFromData($columns, $loop = false)
}
/**
- * Get Total count of data items
+ * Get Total count of data items.
*
* @return int
*/
@@ -546,9 +556,11 @@ public function getTotalCountFromData($maxResults = null)
/**
* Prepares string to have almost the same behaviour as with a database,
- * removing accents and latin special chars
- * @param mixed $inputString
- * @param string $type for array type, will serialize datas
+ * removing accents and latin special chars.
+ *
+ * @param mixed $inputString
+ * @param string $type for array type, will serialize datas
+ *
* @return string the input, serialized for arrays or without accents for strings
*/
protected function prepareStringForLikeCompare($input, $type = null)
@@ -558,14 +570,29 @@ protected function prepareStringForLikeCompare($input, $type = null)
} else {
$outputString = $this->removeAccents($input);
}
+
return $outputString;
}
private function removeAccents($str)
{
- $entStr = htmlentities($str, ENT_NOQUOTES, "UTF-8");
+ if (!is_string($str)) {
+ return $str; // Retourne l'entrée telle quelle si ce n'est pas une chaîne
+ }
+ $entStr = htmlentities($str, ENT_NOQUOTES, 'UTF-8');
$noaccentStr = preg_replace('#&([A-za-z])(?:acute|cedil|circ|grave|orn|ring|slash|th|tilde|uml);#', '\1', $entStr);
return preg_replace('#&([A-za-z]{2})(?:lig);#', '\1', $noaccentStr);
}
+
+ protected function prepareColumnValues(Column $column, $values)
+ {
+ $existingValues = $column->getValues();
+ if (!empty($existingValues)) {
+ $intersect = array_intersect_key($existingValues, $values);
+ $values = array_replace($values, $intersect);
+ }
+
+ return $values;
+ }
}
diff --git a/Grid/Source/Vector.php b/Grid/Source/Vector.php
index 7e6e7560..ce2c2657 100644
--- a/Grid/Source/Vector.php
+++ b/Grid/Source/Vector.php
@@ -12,10 +12,19 @@
namespace APY\DataGridBundle\Grid\Source;
-use APY\DataGridBundle\Grid\Column;
+use APY\DataGridBundle\Grid\Column\ArrayColumn;
+use APY\DataGridBundle\Grid\Column\BooleanColumn;
+use APY\DataGridBundle\Grid\Column\Column;
+use APY\DataGridBundle\Grid\Column\DateColumn;
+use APY\DataGridBundle\Grid\Column\DateTimeColumn;
+use APY\DataGridBundle\Grid\Column\NumberColumn;
+use APY\DataGridBundle\Grid\Column\TextColumn;
+use APY\DataGridBundle\Grid\Column\UntypedColumn;
+use APY\DataGridBundle\Grid\Rows;
/**
- * Vector is really an Array
+ * Vector is really an Array.
+ *
* @author dellamowica
*/
class Vector extends Source
@@ -23,26 +32,30 @@ class Vector extends Source
/**
* @var array
*/
- protected $data = array();
+ protected $data = [];
/**
* either a column name as a string
- * or an array of names of columns
+ * or an array of names of columns.
+ *
* @var mixed
*/
protected $id = null;
/**
- * Array of columns
+ * Array of columns.
+ *
* @var Column[]
*/
protected $columns;
/**
- * Creates the Vector and sets its data
+ * Creates the Vector and sets its data.
+ *
* @param array $data
+ * @param array $columns
*/
- public function __construct(array $data, array $columns = array())
+ public function __construct(array $data, array $columns = [])
{
if (!empty($data)) {
$this->setData($data);
@@ -60,21 +73,21 @@ public function initialise($container)
protected function guessColumns()
{
- $guessedColumns = array();
+ $guessedColumns = [];
$dataColumnIds = array_keys(reset($this->data));
foreach ($dataColumnIds as $id) {
if (!$this->hasColumn($id)) {
- $params = array(
- 'id' => $id,
- 'title' => $id,
- 'source' => true,
+ $params = [
+ 'id' => $id,
+ 'title' => $id,
+ 'source' => true,
'filterable' => true,
- 'sortable' => true,
- 'visible' => true,
- 'field' => $id,
- );
- $guessedColumns[] = new Column\UntypedColumn($params);
+ 'sortable' => true,
+ 'visible' => true,
+ 'field' => $id,
+ ];
+ $guessedColumns[] = new UntypedColumn($params);
}
}
@@ -84,12 +97,12 @@ protected function guessColumns()
$iteration = min(10, count($this->data));
foreach ($this->columns as $c) {
- if (!$c instanceof Column\UntypedColumn) {
+ if (!$c instanceof UntypedColumn) {
continue;
}
$i = 0;
- $fieldTypes = array();
+ $fieldTypes = [];
foreach ($this->data as $row) {
if (!isset($row[$c->getId()])) {
@@ -101,13 +114,12 @@ protected function guessColumns()
if ($fieldValue !== '' && $fieldValue !== null) {
if (is_array($fieldValue)) {
$fieldTypes['array'] = 1;
- } elseif($fieldValue instanceof \DateTime) {
+ } elseif ($fieldValue instanceof \DateTime) {
if ($fieldValue->format('His') === '000000') {
$fieldTypes['date'] = 1;
} else {
$fieldTypes['datetime'] = 1;
}
-
} elseif (strlen($fieldValue) >= 3 && strtotime($fieldValue) !== false) {
$dt = new \DateTime($fieldValue);
if ($dt->format('His') === '000000') {
@@ -143,33 +155,32 @@ protected function guessColumns()
/**
* @param \APY\DataGridBundle\Grid\Columns $columns
- * @return null
*/
public function getColumns($columns)
{
$token = empty($this->id); //makes the first column primary by default
foreach ($this->columns as $c) {
- if ($c instanceof Column\UntypedColumn) {
+ if ($c instanceof UntypedColumn) {
switch ($c->getType()) {
case 'date':
- $column = new Column\DateColumn($c->getParams());
+ $column = new DateColumn($c->getParams());
break;
case 'datetime':
- $column = new Column\DateTimeColumn($c->getParams());
+ $column = new DateTimeColumn($c->getParams());
break;
case 'boolean':
- $column = new Column\BooleanColumn($c->getParams());
+ $column = new BooleanColumn($c->getParams());
break;
case 'number':
- $column = new Column\NumberColumn($c->getParams());
+ $column = new NumberColumn($c->getParams());
break;
case 'array':
- $column = new Column\ArrayColumn($c->getParams());
+ $column = new ArrayColumn($c->getParams());
break;
case 'text':
default:
- $column = new Column\TextColumn($c->getParams());
+ $column = new TextColumn($c->getParams());
break;
}
} else {
@@ -188,10 +199,12 @@ public function getColumns($columns)
/**
* @param \APY\DataGridBundle\Grid\Column\Column[] $columns
- * @param int $page Page Number
- * @param int $limit Rows Per Page
- * @param int $gridDataJunction Grid data junction
- * @return \APY\DataGridBundle\Grid\Rows
+ * @param int $page Page Number
+ * @param int $limit Rows Per Page
+ * @param int $maxResults Max rows
+ * @param int $gridDataJunction Grid data junction
+ *
+ * @return Rows
*/
public function execute($columns, $page = 0, $limit = 0, $maxResults = null, $gridDataJunction = Column::DATA_CONJUNCTION)
{
@@ -210,11 +223,12 @@ public function getTotalCount($maxResults = null)
public function getHash()
{
- return __CLASS__.md5(implode('', array_map(function ($c) { return $c->getId(); }, $this->columns)));
+ return __CLASS__ . md5(implode('', array_map(fn($c) => $c->getId(), $this->columns)));
}
/**
- * sets the primary key
+ * sets the primary key.
+ *
* @param mixed $id either a string or an array of strings
*/
public function setId($id)
@@ -223,8 +237,18 @@ public function setId($id)
}
/**
- * Set a two-dimentional array
+ * @return mixed
+ */
+ public function getId()
+ {
+ return $this->id;
+ }
+
+ /**
+ * Set a two-dimentional array.
+ *
* @param array $data
+ *
* @throws \InvalidArgumentException
*/
public function setData($data)
@@ -235,12 +259,14 @@ public function setData($data)
throw new \InvalidArgumentException('Data should be an array with content');
}
+ // This seems to exclude ...
if (is_object(reset($this->data))) {
foreach ($this->data as $key => $object) {
$this->data[$key] = (array) $object;
}
}
+ // ... this other (or vice versa)
$firstRaw = reset($this->data);
if (!is_array($firstRaw) || empty($firstRaw)) {
throw new \InvalidArgumentException('Data should be a two-dimentional array');
@@ -266,13 +292,4 @@ protected function hasColumn($id)
return false;
}
-
- protected function getColumn($id)
- {
- foreach ($this->columns as $c) {
- if ($id === $c->getId()) {
- return $c;
- }
- }
- }
}
diff --git a/Grid/Type/GridType.php b/Grid/Type/GridType.php
new file mode 100644
index 00000000..fda9d057
--- /dev/null
+++ b/Grid/Type/GridType.php
@@ -0,0 +1,92 @@
+setRoute($options['route'])
+ ->setRouteParameters($options['route_parameters'])
+ ->setPersistence($options['persistence'])
+ ->setPage($options['page'])
+ ->setMaxResults($options['max_results'])
+ ->setMaxPerPage($options['max_per_page'])
+ ->setFilterable($options['filterable'])
+ ->setSortable($options['sortable'])
+ ->setSortBy($options['sort_by'])
+ ->setOrder($options['order'])
+ ->setGroupBy($options['group_by']);
+
+ if (!empty($options['source'])) {
+ $builder->setSource($options['source']);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ $resolver->setDefaults([
+ 'source' => null,
+ 'group_by' => null,
+ 'sort_by' => null,
+ 'order' => 'asc',
+ 'page' => 1,
+ 'route' => '',
+ 'route_parameters' => [],
+ 'persistence' => false,
+ 'max_per_page' => 10,
+ 'max_results' => null,
+ 'filterable' => true,
+ 'sortable' => true,
+ ]);
+
+ $allowedTypes = [
+ 'source' => ['null', 'APY\DataGridBundle\Grid\Source\Source'],
+ 'group_by' => ['null', 'string', 'array'],
+ 'route_parameters' => 'array',
+ 'persistence' => 'bool',
+ 'filterable' => 'bool',
+ 'sortable' => 'bool',
+ ];
+ $allowedValues = [
+ 'order' => ['asc', 'desc'],
+ ];
+ if (method_exists($resolver, 'setDefault')) {
+ // Symfony 2.6.0 and up
+ foreach ($allowedTypes as $option => $types) {
+ $resolver->setAllowedTypes($option, $types);
+ }
+
+ foreach ($allowedValues as $option => $values) {
+ $resolver->setAllowedValues($option, $values);
+ }
+ } else {
+ $resolver->setAllowedTypes($allowedTypes);
+ $resolver->setAllowedValues($allowedValues);
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getName()
+ {
+ return 'grid';
+ }
+}
diff --git a/LICENSE b/LICENSE
index 969fc781..c2f017f0 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,4 +1,4 @@
-Copyright (c) 2011-2014 Stanislav Turza - Abhoryo
+Copyright (c) 2011-2017 Stanislav Turza - Abhoryo
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
@@ -16,4 +16,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
\ No newline at end of file
+THE SOFTWARE.
diff --git a/README.md b/README.md
index 4d2649ab..503a98f0 100644
--- a/README.md
+++ b/README.md
@@ -1,60 +1,50 @@
-Datagrid for Symfony2 inspired by Zfdatagrid and Magento Grid.
-This bundle was initiated by Stanislav Turza (Sorien).
-**Version**: 2.1-dev - master-dev
-**Compatibility**: Symfony >= 2.0.0, Twig >= 1.5.0
+# APYDataGrid Bundle
-[](http://travis-ci.org/Abhoryo/APYDataGridBundle)
+This **Symfony Bundle** allows you to create wonderful grid based on data or entities of your projet.
-See [CHANGELOG](https://github.com/Abhoryo/APYDataGridBundle/blob/master/CHANGELOG.md) and [UPGRADE 2.0](https://github.com/Abhoryo/APYDataGridBundle/blob/master/UPGRADE-2.0.md)
+[](http://travis-ci.org/APY/APYDataGridBundle) [](https://coveralls.io/github/APY/APYDataGridBundle?branch=test-improvement)
## Features
-
-- Supports Entity (ORM), Document (ODM) and Vector (Array) sources
-- Sortable and Filterable with operators (Comparison operators, range, starts/ends with, (not) contains, is (not) defined, regex)
+This bundle allow you to create listing with many features that you can expect :
+- Various data sources : supports **Entity** (ORM), **Document** (ODM) and **Vector** (Array) sources
+- Data manipulation : **Sortable** and **Filterable** with many operators
- Auto-typing columns (Text, Number, Boolean, Array, DateTime, Date, ...)
-- Locale support for DateTime, Date and Number columns (Decimal, Currency, Percent, Duration, Scientific, Spell out)
+- Locale support for columns and data (DateTime, Date and Number columns)
- Input, Select, checkbox and radio button filters filled with the data of the grid or an array of values
- Export (CSV, Excel, _PDF_, XML, JSON, HTML, ...)
-- Mass actions
-- Row actions
+- Mass actions, Row actions
- Supports mapped fields with Entity source
- Securing the columns, actions and export with security roles
- Annotations and PHP configuration
- External filters box
- Ajax loading
- Pagination (You can also use Pagerfanta)
-- Column width and column align
-- Prefix translated titles
- Grid manager for multi-grid on the same page
- Groups configuration for ORM and ODM sources
-- Easy templates overriding (twig)
+- Easy templates overriding (Twig)
- Custom columns and filters creation
-- ...
+- *and many more*
-## Documentation
+## Installation, documentation
-See the [summary](https://github.com/Abhoryo/APYDataGridBundle/blob/master/Resources/doc/summary.md).
+See the [summary](https://github.com/APY/APYDataGridBundle/blob/master/Resources/doc/summary.md).
## Screenshot
-Full example with this [CSS style file](https://github.com/Abhoryo/APYDataGridBundle/blob/master/Resources/doc/grid_configuration/working_example.css):
+Full example with this [CSS style file](https://github.com/APY/APYDataGridBundle/blob/master/Resources/doc/grid_configuration/working_example.css):
-
+
Simple example with the external filter box in english:
-
+
Same example in french:
-
-
-Data used in these screenshots (this is a phpMyAdmin screenshot):
+
-
-
-## Simple grid with an ORM source
+## Example of a simple grid with an ORM source
```php
APY\DataGridBundle\Grid\Column\DateColumn
APY\DataGridBundle\Grid\Column\TimeColumnAPY\DataGridBundle\Grid\Column\ArrayColumn
+ APY\DataGridBundle\Grid\Column\SimpleArrayColumnAPY\DataGridBundle\Grid\Column\BlankColumnAPY\DataGridBundle\Grid\Column\RankColumnAPY\DataGridBundle\Grid\Column\JoinColumn
@@ -46,6 +47,10 @@
+
+
+
+
diff --git a/Resources/config/grid.yml b/Resources/config/grid.yml
new file mode 100644
index 00000000..fe1bd1da
--- /dev/null
+++ b/Resources/config/grid.yml
@@ -0,0 +1,59 @@
+services:
+ # Core
+ apy_grid.factory:
+ class: APY\DataGridBundle\Grid\GridFactory
+ arguments: ['@service_container', '@security.authorization_checker', '@twig', '@apy_grid.registry']
+ apy_grid.registry:
+ class: APY\DataGridBundle\Grid\GridRegistry
+ APY\DataGridBundle\Grid\GridFactoryInterface:
+ alias: 'apy_grid.factory'
+ APY\DataGridBundle\Grid\GridRegistryInterface:
+ alias: 'apy_grid.registry'
+
+ # Types
+ apy_grid.type.grid:
+ class: APY\DataGridBundle\Grid\Type\GridType
+ tags:
+ - { name: apy_grid.type }
+
+ # Columns
+ apy_grid.column.text:
+ class: APY\DataGridBundle\Grid\Column\TextColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.array:
+ class: APY\DataGridBundle\Grid\Column\ArrayColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.blank:
+ class: APY\DataGridBundle\Grid\Column\BlankColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.boolean:
+ class: APY\DataGridBundle\Grid\Column\BooleanColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.date:
+ class: APY\DataGridBundle\Grid\Column\DateColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.date_time:
+ class: APY\DataGridBundle\Grid\Column\DateTimeColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.join:
+ class: APY\DataGridBundle\Grid\Column\JoinColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.number:
+ class: APY\DataGridBundle\Grid\Column\NumberColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.rank:
+ class: APY\DataGridBundle\Grid\Column\RankColumn
+ tags:
+ - { name: apy_grid.column }
+ apy_grid.column.time:
+ class: APY\DataGridBundle\Grid\Column\TimeColumn
+ tags:
+ - { name: apy_grid.column }
diff --git a/Resources/config/services.xml b/Resources/config/services.xml
index 4e296696..3172cc01 100644
--- a/Resources/config/services.xml
+++ b/Resources/config/services.xml
@@ -20,8 +20,10 @@
-
+
+
+ %apy_data_grid.limits%
@@ -41,26 +43,26 @@
%apy_data_grid.actions_columns_title%
+
+
+
+
-
+ 1
-
-
-
-
-
+
diff --git a/Resources/doc/columns_configuration/annotations/column_annotation_property.md b/Resources/doc/columns_configuration/annotations/column_annotation_property.md
index dd853bb3..51e0ac97 100644
--- a/Resources/doc/columns_configuration/annotations/column_annotation_property.md
+++ b/Resources/doc/columns_configuration/annotations/column_annotation_property.md
@@ -31,8 +31,7 @@ class Product
* @ORM\ManyToOne(targetEntity="Category", inversedBy="products")
* @ORM\JoinColumn(name="category_id", referencedColumnName="id")
*
- * @GRID\Column(field="category.name", title="Category Name")
- * @GRID\Column(field="category.children.name", type="array", title="Category Children")
+ * @GRID\Column(field="category.name", title="category.name", translation_domain="categories")
*/
protected $category;
}
@@ -65,9 +64,11 @@ class Product
|searchOnClick|boolean|false|true or false|Sets the possibility to perform a search on the clicked cell (filterable has to be true)|
|safe|string or false|html|false or see [Escape filters](http://twig.sensiolabs.org/doc/filters/escape.html)|Sets the escape filter|
|usePrefixTitle|boolean|true|true or false|Use the prefixTitle of the grid to render title|
+|translation_domain|string|null||The translation domain that will be used for the title|
**Note 1**: Every attribute has a setter and a getter method.
**Note 2**: With the `values` attributes, if `type1` is found, the grid displays the value `Type 1`.
**Note 3**: If operators are not visible, filtering is performed with the default operator.
+**Note 4**: If you have and `id` field and want to use another field as primary, you need to set `primary=false` on the id field.
## Title translation
diff --git a/Resources/doc/columns_configuration/annotations/dql_function.md b/Resources/doc/columns_configuration/annotations/dql_function.md
index 0705b66d..48e539e1 100644
--- a/Resources/doc/columns_configuration/annotations/dql_function.md
+++ b/Resources/doc/columns_configuration/annotations/dql_function.md
@@ -103,3 +103,15 @@ class Article {
`sales.name:otherFunction:string` turns into `otherFunction(_sales.name, 'string')` in DQL
`other:count:distinct` turns into `count(DISTINCT _a.other)` in DQL
+
+
+## Using GridBuilder
+```php
+setGroupBy('id') //important to setGroupBy otherwise the column will not aggregate
+ ->add('comments.id:count', 'text' ['title' => 'Number of Comments']);
+```
diff --git a/Resources/doc/columns_configuration/filters/select_filter.md b/Resources/doc/columns_configuration/filters/select_filter.md
old mode 100755
new mode 100644
index 774b84f2..06504c88
--- a/Resources/doc/columns_configuration/filters/select_filter.md
+++ b/Resources/doc/columns_configuration/filters/select_filter.md
@@ -40,7 +40,7 @@ From values:
/**
* @ORM\Column(type="string", length="32")
*
- * @GRID\Column(filter="select", selectFrom="values", values={"type1"="Type 1","type1"="Type 2"})
+ * @GRID\Column(filter="select", selectFrom="values", values={"type1"="Type 1","type2"="Type 2"})
*/
protected $type;
...
diff --git a/Resources/doc/columns_configuration/index.md b/Resources/doc/columns_configuration/index.md
new file mode 100644
index 00000000..c1b5b39e
--- /dev/null
+++ b/Resources/doc/columns_configuration/index.md
@@ -0,0 +1,35 @@
+# Columns Configuration with Annotations
+
+## Annotations
+
+* [Source Annotation](annotations/source_annotation.md)
+* [Column Annotation for a property](annotations/column_annotation_property.md)
+* [Column Annotation for a class](annotations/column_annotation_class.md)
+* [ORM Association Mapping](annotations/association_mapping.md)
+* [DQL Functions](annotations/dql_function.md)
+
+## Column Types References
+
+* [Text Column](types/text_column.md)
+* [Number Column](types/number_column.md)
+ * [Decimal](types/number_column.md)
+ * [Currency](types/number_column.md)
+ * [Percent](types/number_column.md)
+ * [Duration](types/number_column.md)
+ * [Scientific](types/number_column.md)
+ * [Spell Out](types/number_column.md)
+* [Boolean Column](types/boolean_column.md)
+* [DateTime Column](types/datetime_column.md)
+* [Date Column](types/date_column.md)
+* [_Time_](types/time_column.md)
+* [Array Column](types/array_column.md)
+* [Blank Column](types/blank_column.md)
+* [Rank Column](types/rank_column.md)
+* [Join Column](types/join_column.md)
+* [Create your column](types/create_column.md)
+
+## Filters
+
+* [Input Filter](filters/input_filter.md)
+* [Select Filter](filters/select_filter.md)
+* [Create a filter](filters/create_filter.md)
diff --git a/Resources/doc/columns_configuration/types/boolean_column.md b/Resources/doc/columns_configuration/types/boolean_column.md
index 6f55bb1f..b0659288 100644
--- a/Resources/doc/columns_configuration/types/boolean_column.md
+++ b/Resources/doc/columns_configuration/types/boolean_column.md
@@ -15,7 +15,7 @@ See [Select filter - additionnal attributes](../filters/select_filter.md#additio
## Filter
### Valid values
-1 and 0 ####### A vrifier pour les entier
+1 and 0 ####### A vérifier pour les entier
### Default Operator: `eq`
diff --git a/Resources/doc/columns_configuration/types/create_column.md b/Resources/doc/columns_configuration/types/create_column.md
index 3c7cd717..bf8b8e77 100644
--- a/Resources/doc/columns_configuration/types/create_column.md
+++ b/Resources/doc/columns_configuration/types/create_column.md
@@ -112,8 +112,8 @@ class VideoColumn extends Column
In your twig template:
```janjo
-
-{% extends 'APYDataGridBundle::blocks.html.twig' %}
+
+{% extends '@APYDataGrid/blocks.html.twig' %}
{% block grid_column_type_video_cell %}
{# Show your player with the file path store in the variable {{ value }} #}
diff --git a/Resources/doc/columns_configuration/types/date_column.md b/Resources/doc/columns_configuration/types/date_column.md
index bb218aa3..a0ed0a42 100644
--- a/Resources/doc/columns_configuration/types/date_column.md
+++ b/Resources/doc/columns_configuration/types/date_column.md
@@ -1,7 +1,7 @@
Date Column
===========
-The Date Column extends the [DateTime Column](datetime_column.md) and the default fallback format is `Y-m-d`.
+The Date Column extends the [DateTime Column](datetime_column.md) and the default fallback format and filter input format are `Y-m-d`.
With this column, the time part of a datetime value is ignored when you filter the column.
So, if you filter the column with the value `2012-04-26` or `2012-04-26 12:23:45` and with the operator `=`, the query will be `date >= '2012-04-26 0:00:00' AND date <= '2012-04-26 23:59:59'`.
diff --git a/Resources/doc/columns_configuration/types/datetime_column.md b/Resources/doc/columns_configuration/types/datetime_column.md
index 0db2095b..c1027b9c 100644
--- a/Resources/doc/columns_configuration/types/datetime_column.md
+++ b/Resources/doc/columns_configuration/types/datetime_column.md
@@ -13,7 +13,11 @@ See [Column annotation for properties](../annotations/column_annotation_property
|Attribute|Type|Default value|Possible values|Description|
|:--:|:--|:--|:--|:--|
-|format|string|||Define this attribute if you want to force the format of the displayed value. (e.g. "Y-m-d H:i:s")|
+|format|string| | |Define this attribute if you want to force the format of the displayed value. (e.g. "Y-m-d H:i:s")|
+|timezone|string|System default timezone| |The timezone to use for rendering. (e.g. "Europe/Paris")|
+|inputFormat|string|"Y-m-d H:i:s"| |Define this attribute if you want to force the format of the filtered value. (e.g. "Y-m-d H:i:s")|
+
+**Note**: If you want to filter using date input (and not datetime input), you should use the [Date Column](date_column.md) type instead and configure the display format to render the time (e.g. "Y-m-d H:i:s").
## Filter
#### Valid values
@@ -40,4 +44,4 @@ Wrong values are ignored.
|btw|Between exclusive|
|btwe|Between inclusive|
|isNull|Is not defined|
-|isNotNull|Is defined|
\ No newline at end of file
+|isNotNull|Is defined|
diff --git a/Resources/doc/configuration.md b/Resources/doc/configuration.md
new file mode 100644
index 00000000..9f914ba6
--- /dev/null
+++ b/Resources/doc/configuration.md
@@ -0,0 +1,21 @@
+# APYDataGrid Configuration Reference
+
+All available configuration options are listed below with their default values.
+
+```yaml
+apy_data_grid:
+ limits: [20, 50, 100]
+ persistence: false
+ theme: '@APYDataGrid/blocks.html.twig'
+ no_data_message: "No data"
+ no_result_message: "No result"
+ actions_columns_size: -1
+ actions_columns_title: "Actions"
+ actions_columns_separator: " "
+ pagerfanta:
+ enable: false
+ view_class: "Pagerfanta\\View\\DefaultView"
+ options:
+ prev_message: "«"
+ next_message: "»"
+```
diff --git a/Resources/doc/export/create_export.md b/Resources/doc/export/create_export.md
index 13cfaec5..40f3d114 100644
--- a/Resources/doc/export/create_export.md
+++ b/Resources/doc/export/create_export.md
@@ -159,7 +159,7 @@ We'll try to create a CSV export.
**Note**: These functions return the array of titles only if titles are visible.
- #### Export::getFlatGridData and Export::getRawFlatGridData
+ #### Export::getFlatGridData and Export::getFlatRawGridData
These functions return an flat array of rows. If titles are visible the first index of the array is the array of titles.
@@ -223,7 +223,7 @@ We'll try to create a CSV export.
}
```
- Voil, you can export your grid in a csv file.
+ Voilà, you can export your grid in a csv file.
7. **Additional parameters**
diff --git a/Resources/doc/export/index.md b/Resources/doc/export/index.md
new file mode 100644
index 00000000..33409648
--- /dev/null
+++ b/Resources/doc/export/index.md
@@ -0,0 +1,35 @@
+# Export
+
+APYDataGrid bundle provides different ways for export your datas. This bundle proposes native exports such as a CSV or a JSON export and library-dependent exports such as Excel and PDF exports but everything is made that it is really easy to create your own export.
+
+> Note: An export don't export mass action and row actions columns.
+
+## Native Exports
+
+* [CSV Export](native_exports/CSV_export.md)
+* [DSV Export](native_exports/DSV_export.md)
+* [Excel Export](native_exports/Excel_export.md)
+* [JSON Export](native_exports/JSON_export.md)
+* [SCVS Export](native_exports/SCVS_export.md)
+* [TSV Export](native_exports/TSV_export.md)
+* [XML Export](native_exports/XML_export.md)
+
+## External Library Exports
+
+### With PHPExcel
+
+Add the following package to your composer.json file:
+
+```bash
+$ composer require phpoffice/phpexcel "dev-master"
+```
+
+* [PHPExcel Excel 2007 Export](library-dependent_exports/PHPExcel/PHPExcel_excel2007_export.md)
+* [PHPExcel Excel 2003 Export](library-dependent_exports/PHPExcel/PHPExcel_excel2003_export.md)
+* [PHPExcel Excel 5 (97-2003) Export](library-dependent_exports/PHPExcel/PHPExcel_excel5_export.md)
+* [PHPExcel Simple HTML Export](library-dependent_exports/PHPExcel/PHPExcel_HTML_export.md)
+* [PHPExcel simple PDF export](library-dependent_exports/PHPExcel/PHPExcel_PDF_export.md)
+
+## Cook Book
+
+* [How to create your custom export](create_export.md)
\ No newline at end of file
diff --git a/Resources/doc/export/library-dependent_exports/PHPExcel/PHPExcel_installation.md b/Resources/doc/export/library-dependent_exports/PHPExcel/PHPExcel_installation.md
deleted file mode 100644
index 41101b06..00000000
--- a/Resources/doc/export/library-dependent_exports/PHPExcel/PHPExcel_installation.md
+++ /dev/null
@@ -1,16 +0,0 @@
-PHPExcel installation
-=====================
-
-Add the foolowing package to your composer.json file:
-```js
-{
- "require": {
- "phpoffice/phpexcel": "dev-master"
- }
-}
-```
-
-Execute this command:
-```bash
-$ php composer.phar update phpoffice/phpexcel
-```
diff --git a/Resources/doc/features.md b/Resources/doc/features.md
new file mode 100644
index 00000000..e2e8c114
--- /dev/null
+++ b/Resources/doc/features.md
@@ -0,0 +1,40 @@
+# APYDataGrid Bundle Features
+
+- Supports Entity (ORM), Document (ODM) and Vector (Array) sources
+- Sortable and Filterable with operators (Comparison operators, range, starts/ends with, (not) contains, is (not) defined, regex)
+- Auto-typing columns (Text, Number, Boolean, Array, DateTime, Date, ...)
+- Locale support for DateTime, Date and Number columns (Decimal, Currency, Percent, Duration, Scientific, Spell out)
+- Input, Select, checkbox and radio button filters filled with the data of the grid or an array of values
+- Export (CSV, Excel, _PDF_, XML, JSON, HTML, ...)
+- Mass actions
+- Row actions
+- Supports mapped fields with Entity source
+- Securing the columns, actions and export with security roles
+- Annotations and PHP configuration
+- External filters box
+- Ajax loading
+- Pagination (You can also use Pagerfanta)
+- Column width and column align
+- Prefix translated titles
+- Grid manager for multi-grid on the same page
+- Groups configuration for ORM and ODM sources
+- Easy templates overriding (twig)
+- Custom columns and filters creation
+
+## Screenshot
+
+Full example with this [CSS style file](https://github.com/APY/APYDataGridBundle/blob/master/Resources/doc/grid_configuration/working_example.css):
+
+
+
+Simple example with the external filter box in english:
+
+
+
+Same example in french:
+
+
+
+Data used in these screenshots (this is a phpMyAdmin screenshot):
+
+
\ No newline at end of file
diff --git a/Resources/doc/grid.md b/Resources/doc/grid.md
new file mode 100644
index 00000000..948ec58b
--- /dev/null
+++ b/Resources/doc/grid.md
@@ -0,0 +1,154 @@
+DataGrid
+========
+
+An entity
+---------
+```php
+class Product
+{
+ /**
+ * @var int
+ */
+ protected $id;
+
+ /**
+ * @var string
+ */
+ protected $name;
+
+ /**
+ * @var DateTime
+ */
+ protected $createdAt;
+
+ /**
+ * @var string
+ */
+ protected $status;
+
+ // Getters and setters ...
+}
+```
+Creating the grid from the grid builder
+---------------------------------------
+
+Creating a grid requires relatively little code because the grid objects are built with a "grid builder".
+The grid builder's purpose is to allow you to write simple grid, and have it do all the heavy-lifting of actually building the grid.
+
+```php
+class ProductController extends Controller
+{
+
+ public function listAction(Request $request)
+ {
+ // Creates the builder
+ $gridBuilder = $this->createGridBuilder(new Entity('MyProjectBundle:Product'), [
+ 'persistence' => true,
+ 'route' => 'product_list',
+ 'filterable' => false,
+ 'sortable' => false,
+ 'max_per_page' => 20,
+ ]);
+
+ // Creates columns
+ $grid = $gridBuilder
+ ->add('id', 'number', [
+ 'title' => '#',
+ 'primary' => 'true',
+ ])
+ ->add('name', 'text')
+ ->add('created_at', 'datetime', [
+ 'field' => 'createdAt',
+ ])
+ ->add('status', 'text')
+ ->getGrid();
+
+ // Handles filters, sorts, exports, ...
+ $grid->handleRequest($request);
+
+ // Renders the grid
+ return $this->render('MyProjectBundle:Product:list', ['grid' => $grid]);
+ }
+
+ /**
+ * @return GridBuilder
+ */
+ public function createGridBuilder(Source $source = null, array $options = [])
+ {
+ return $this->container->get('apy_grid.factory')->createBuilder('grid', $source, $options);
+ }
+}
+```
+
+Creating a grid from a type
+---------------------------
+
+A better practice is to build the grid in a separate, standalone PHP class, which can then be reused anywhere in your application.
+Create a new class that will house the logic for building the product grid:
+
+```php
+class ProductListType extends GridType
+{
+ public function buildGrid(GridBuilder $builder, array $options = [])
+ {
+ parent::buildGrid($builder, $options);
+
+ $builder
+ ->add('id', 'number', [
+ 'title' => '#',
+ 'primary' => 'true',
+ ])
+ ->add('name', 'text')
+ ->add('created_at', 'datetime', [
+ 'field' => 'createdAt',
+ ])
+ ->add('status', 'text');
+ }
+
+ public function configureOptions(OptionsResolver $resolver)
+ {
+ parent::configureOptions($resolver);
+
+ $resolver->setDefaults([
+ 'source' => new Entity('MyProjectBundle:Product'),
+ 'persistence' => true,
+ 'route' => 'product_list',
+ 'filterable' => false,
+ 'sortable' => false,
+ 'max_per_page' => 20,
+ ]);
+ }
+
+ public function getName()
+ {
+ return 'product_list';
+ }
+}
+```
+
+It can be used to quickly build a grid object in the controller:
+
+```php
+class ProductController extends Controller
+{
+
+ public function listAction(Request $request)
+ {
+ // Creates the grid from the type
+ $grid = $this->createGrid(new ProductListType());
+
+ // Handles filters, sorts, exports, ...
+ $grid->handleRequest($request);
+
+ return $this->render('MyProjectBundle:Product:list', ['grid' => $grid]);
+ }
+
+ /**
+ * @return Grid
+ */
+ public function createGrid($type, Source $source = null, array $options = [])
+ {
+ $this->container->get('apy_grid.factory')->create($type, $source, $options);
+ }
+}
+```
diff --git a/Resources/doc/grid_configuration/add_actions_column.md b/Resources/doc/grid_configuration/add_actions_column.md
index 70e4e228..587991de 100644
--- a/Resources/doc/grid_configuration/add_actions_column.md
+++ b/Resources/doc/grid_configuration/add_actions_column.md
@@ -25,7 +25,7 @@ $grid->addRowAction($rowAction1);
// OR add a second row action directly to a new action column
$rowAction2 = new RowAction('Edit', 'route_to_edit');
-$actionsColumn2 = new ActionsColumn($column, $title, array(rowAction2), $separator);
+$actionsColumn2 = new ActionsColumn($column, $title, array($rowAction2), $separator);
$grid->addColumn($actionsColumn2, $position2);
...
```
@@ -70,7 +70,7 @@ $grid->addRowAction($rowAction1);
// OR add a second row action directly to a new action column
$rowAction2 = new RowAction('Edit', 'route_to_edit');
-$actionsColumn2 = new ActionsColumn('info_column_2', 'Actions 3', array(rowAction2));
+$actionsColumn2 = new ActionsColumn('info_column_2', 'Actions 3', array($rowAction2));
$grid->addColumn($actionsColumn2, 2);
...
```
diff --git a/Resources/doc/grid_configuration/index.md b/Resources/doc/grid_configuration/index.md
new file mode 100644
index 00000000..fffcaf59
--- /dev/null
+++ b/Resources/doc/grid_configuration/index.md
@@ -0,0 +1,102 @@
+# Grid Configuration with PHP
+
+#### [Set the identifier of the grid](set_grid_identifier.md)
+You can set the identifier of a grid to manage easily the grid with css and javascript for instance.
+
+#### [Set the persistence of the grid](set_grid_persistence.md)
+By default, filters, page and order are reset when you quit the page where your grid is. If you set to true the persistence, its parameters are kept until you close your web browser or you kill the session cookie yourself.
+
+#### [Pagination](set_limits.md)
+Define the selector of the number of items per page
+
+#### [Set max results](set_max_results.md)
+Set max results.
+
+#### [Add column](add_column.md)
+You can add a column to the grid. You can fill it with the row manipulator, in your template or tell the grid what field the column will be mapped.
+
+#### [Add row action](add_row_action.md)
+A row action is an action performed on the current row. It's represented by a route to a controller with the identifier of the row.
+
+#### [Add multiple row actions columns](add_actions_column.md)
+You can create other columns of row actions and choose the position of these ones.
+
+#### [Add mass action](add_mass_action.md)
+A mass action is like a row action but over many lines at the same time.
+
+#### [Add a native delete mass action](add_delete_mass_action.md)
+This mass action calls the delete method of the source.
+
+#### [Add export](add_export.md)
+
+
+#### [Manipulate rows data](manipulate_rows_data.md)
+You can set a callback to manipulate the row of the grid.
+
+#### [Manipulate column render cell](manipulate_column_render_cell.md)
+You can set a callback to manipulate the render of a cell.
+
+#### [Manipulate the source query](manipulate_query.md)
+The Entity Source provides two ways of manipulating the query which is used for generating the grid.
+
+#### [Manipulate the count query (source Entity only)](manipulate_count_query.md)
+The grid requires the total number of results (COUNT (...)). The grid clones the source QueryBuilder and wraps it with a COUNT DISTINCT clause.
+
+#### [Manipulate columns](manipulate_column.md)
+You can manipulate the behavior of a column.
+
+#### [Manipulate row action rendering](manipulate_row_action_rendering.md)
+You can set a callback to manipulate the rendering of an action.
+
+#### [Hide or show columns](hide_show_columns.md)
+These functions are helpers to manipulate columns.
+
+#### [Set columns order](set_columns_order.md)
+You can already define the order of the columns with the columns option of the Source annotation.
+
+#### [Set a default page](set_default_page.md)
+You can define a default page. This page will be used on each new session of the grid.
+
+#### [Set a default order](set_default_order.md)
+You can define a default order. This order will be used on each new session of the grid.
+
+#### [Set a default items per page](set_default_limit.md)
+You can define a default limit. This limit will be used on each new session of the grid.
+
+#### [Set default filters](set_default_filters.md)
+You can define default filters. These values will be used on each new session of the grid.
+
+#### [Set permanent filters](set_permanent_filters.md)
+You can define permanent filters. These values will be used every time and the filter part will be disable for columns which have a permanent filter.
+
+#### [Set the no data message](set_no_data_message.md)
+When you render a grid with no data in the source, the grid isn't displayed and a no data message is displayed.
+
+#### [Set the no result message](set_no_result_message.md)
+When you render a grid with no result after a filtering, a no result message is displayed in a unique row.
+
+#### [Always show the grid](always_show_grid.md)
+When you render a grid with no data in the source, the grid isn't displayed and a no data message is displayed.
+
+#### [Set a title prefix](set_prefix_titles.md)
+You can define a prefix title for all columns of the grid.
+
+#### [Set the size of the actions colum](set_size_actions_column.md)
+Set the size of the actions column.
+
+#### [Set the title of the actions colum](set_title_actions_column.md)
+Set the title of the actions column.
+
+#### [Set data to avoid calling the database](set_data.md)
+You can use fetched data to avoid unnecessary queries.
+
+#### [Grid Response helper](grid_response.md)
+The getGridResponse method is an helper which manage the redirection, export and the rendering of the grid.
+
+#### [Multi Grid manager](multi_grid_manager.md)
+Handle multiple grids on the same page.
+
+#### [Set the route of the grid](set_grid_route.md)
+The route of a grid is automatically retrieved from the request. But when you render a controller which contains a grid from twig, the route cannot be retrieved so you have to define it.
+
+#### [Working Example](working_example.md)
diff --git a/Resources/doc/grid_configuration/manipulate_count_query.md b/Resources/doc/grid_configuration/manipulate_count_query.md
new file mode 100644
index 00000000..4927af84
--- /dev/null
+++ b/Resources/doc/grid_configuration/manipulate_count_query.md
@@ -0,0 +1,45 @@
+Manipulating the count query builder
+============================
+
+The grid requires the total number of results (COUNT (...)). The grid clones the source QueryBuilder and wraps it with a COUNT DISTINCT clause.
+If you use a lot of aggregation in the source queryBuilder you may encounter performance problems.
+You can manipulate the query before it is processed to remove useless fields for the COUNT clause.
+
+## 1. Using a callback
+
+```php
+manipulateCountQuery($callback);
+
+$grid->setSource($source);
+...
+```
+
+### Method Source::manipulateCountQuery parameters
+
+|parameter|Type|Default value|Description|
+|:--:|:--|:--|:--|:--|
+|callback|[\Closure](http://php.net/manual/en/functions.anonymous.php) or [callable](http://php.net/manual/en/language.types.callable.php)|null|Callback to manipulate the query. Null means no callback.|
+
+### Callback parameters
+
+|parameter|Type|Description|
+|:--:|:--|:--|:--|:--|
+|queryBuilder|instance of QueryBuilder|The QueryBuilder instance before its execution (clone of the source QueryBuilder)|
+
+### Examples
+
+```php
+manipulateCountQuery(
+ function ($queryBuilder)
+ {
+ $queryBuilder->resetDQLPart('select');
+ }
+);
+
+$grid->setSource($source);
+...
+```
diff --git a/Resources/doc/grid_configuration/manipulate_row_action_rendering.md b/Resources/doc/grid_configuration/manipulate_row_action_rendering.md
index 0365e973..730745aa 100644
--- a/Resources/doc/grid_configuration/manipulate_row_action_rendering.md
+++ b/Resources/doc/grid_configuration/manipulate_row_action_rendering.md
@@ -28,6 +28,11 @@ $grid->addRowAction($rowAction);
|action|instance of RowAction|The action|
|row|instance of Row|The current row|
+## Action disabling
+
+The action can be disabled using the manipulate render callback. See the example.
+If the action is disabled, only its title is displayed, with all additional attributes used.
+
## Example
```php
@@ -44,6 +49,10 @@ $rowAction->manipulateRender(
return null;
}
+ if ($row->getField('enabled') == false) {
+ $action->setEnabled(false);
+ }
+
return $action;
}
);
diff --git a/Resources/doc/grid_configuration/multi_grid_manager.md b/Resources/doc/grid_configuration/multi_grid_manager.md
index ea81421a..6225f6d3 100644
--- a/Resources/doc/grid_configuration/multi_grid_manager.md
+++ b/Resources/doc/grid_configuration/multi_grid_manager.md
@@ -69,11 +69,6 @@ $grid2->setSource($source2);
if ($gridManager->isReadyForRedirect())
{
- if ($gridManager->isReadyForExport())
- {
- return $gridManager->getExportResponse();
- }
-
return new RedirectResponse($gridManager->getRouteUrl());
}
else
diff --git a/Resources/doc/grid_configuration/set_grid_persistence.md b/Resources/doc/grid_configuration/set_grid_persistence.md
index 0a407426..17cb5187 100644
--- a/Resources/doc/grid_configuration/set_grid_persistence.md
+++ b/Resources/doc/grid_configuration/set_grid_persistence.md
@@ -3,7 +3,7 @@ Set the persistence of the grid
By default, filters, page and order are reset when you quit the page where your grid is.
-If you set to true the persistence, its parameters are kept until you close your web browser or you kill yourself the cookie of the session.
+If you set to true the persistence, its parameters are kept until you close your web browser or you kill the session cookie yourself.
But don't forget to define an different identifier of your grids else your sessions will be reset by another grid with the same identifier.
## Usage
@@ -37,4 +37,4 @@ $grid->setPersistence(true);
```yml
apy_data_grid:
persistence: true
-```
\ No newline at end of file
+```
diff --git a/Resources/doc/index.md b/Resources/doc/index.md
new file mode 100644
index 00000000..b418bf4c
--- /dev/null
+++ b/Resources/doc/index.md
@@ -0,0 +1,128 @@
+# APY DataGrid Bundle
+
+APYDataGridBundle is a Symfony bundle for create grids for list your Entity (ORM), Document (ODM) and Vector (Array) sources. [APYDataGridBundle](https://github.com/APY/APYDataGridBundle) was initiated by **Stanislav Turza (Sorien)** and inspired by **Zfdatagrid and Magento Grid**.
+
+> You can see [CHANGELOG](CHANGELOG.md) and [UPGRADE 2.0](UPGRADE-2.0.md).
+
+## Prerequisites
+
+This version of the bundle requires Symfony 3.0+.
+
+### Translations
+
+If you wish to use default texts provided in this bundle, you have to make sure you have translator enabled in your config.
+
+```yaml
+# app/config/config.yml
+framework:
+ translator: ~
+```
+
+For more information about translations, check [Symfony documentation](https://symfony.com/doc/current/book/translation.html).
+
+## Installation
+
+### Step 1 : Download APYDataGridBundle using composer
+
+Require the bundle with composer :
+
+```bash
+$ composer require apy/datagrid-bundle
+```
+
+Composer will install the bundle to your project's *vendor/apy/datagrid-bundle* directory.
+
+### Step 2 : Enable the bundle
+
+Enable the bundle in the kernel :
+
+```php
+// app/AppKernel.php
+
+public function registerBundles()
+{
+ $bundles = array(
+ // ...
+ new APY\DataGridBundle\APYDataGridBundle(),
+ // ...
+ );
+}
+```
+
+### Step 3 : Quick start with APYDataGridBundle
+
+#### Create simple grid with an ORM source in your controller
+
+```php
+get('grid');
+
+ // Attach the source to the grid
+ $grid->setSource($source);
+
+ // Return the response of the grid to the template
+ return $grid->getGridResponse('MyProjectMyBundle:myGrid.html.twig');
+ }
+}
+```
+
+#### Create simple configuration of the grid in the entity
+
+```php
+
+{{ grid(grid) }}
+```
+
+> Don't forget to clean your cache !
+
+### Next Steps
+
+Now you have completed the basic installation and configuration of the APYDataGridBundle, you are ready to learn about more advanced features and usages of the bundle.
+
+The following documents are available :
+
+* [Getting Started With APYDataGridBundle](getting_started.md)
+* [Setting the Grid Source](source/index.md)
+* [Display the Grid (Twig template)](template/index.md)
+* [Columns Configuration with Annotations](columns_configuration/index.md)
+* [Grid Configuration with PHP](grid_configuration/index.md)
+* [Export](export/index.md)
+* [APYDataGridBundle Configuration Reference](configuration.md)
diff --git a/Resources/doc/installation.md b/Resources/doc/installation.md
deleted file mode 100644
index 869027c7..00000000
--- a/Resources/doc/installation.md
+++ /dev/null
@@ -1,25 +0,0 @@
-Installation
-============
-
-### Step 1: Download DataGridBundle using Composer
-
-```bash
-$ composer require apy/datagrid-bundle
-```
-
-### Step 2: Enable the bundle
-
-Finally, enable the bundle in the kernel:
-
-``` php
- if you want your data mapped on these columns.
+**Note:**
+
+* Attributes `id` and `field` are required. The `id` is the identifier of your column and `field` is the name of your field to map with you data.
+* Columns are not sourcable and mapped with id by default, you have to define source=true and field= if you want your data mapped on these columns.
## Set a primary field
diff --git a/Resources/doc/summary.md b/Resources/doc/summary.md
index 86e0f445..cc681a3d 100644
--- a/Resources/doc/summary.md
+++ b/Resources/doc/summary.md
@@ -3,7 +3,7 @@ SUMMARY
1. [Introduction](https://github.com/Abhoryo/APYDataGridBundle/blob/master/README.md)
-1. [Installation](installation.md)
+1. [Installation](index.md)
1. [Getting Started with APYDataGridBundle](getting_started.md)
@@ -65,6 +65,7 @@ SUMMARY
1. [Manipulate rows data](grid_configuration/manipulate_rows_data.md)
1. [Manipulate column render cell](grid_configuration/manipulate_column_render_cell.md)
1. [Manipulate the source query](grid_configuration/manipulate_query.md)
+ 1. [Manipulate the count query (source Entity only)](grid_configuration/manipulate_count_query.md)
1. [Manipulate columns](grid_configuration/manipulate_column.md)
1. [Manipulate row action rendering](grid_configuration/manipulate_row_action_rendering.md)
1. [Hide or show columns](grid_configuration/hide_show_columns.md)
diff --git a/Resources/doc/template/cell_rendering.md b/Resources/doc/template/cell_rendering.md
index 11e12db2..982102dc 100644
--- a/Resources/doc/template/cell_rendering.md
+++ b/Resources/doc/template/cell_rendering.md
@@ -37,12 +37,12 @@ However this naming convention is not advised as it is ambiguous. It is only sup
#### Use icons for boolean columns with passed additional parameters
```janjo
-grid(grid, 'MyProjectMyBundle::my_grid_template.html.twig', '', {'imgDir': 'img/'})
+grid(grid, 'my_grid_template.html.twig', '', {'imgDir': 'img/'})
```
```janjo
-
-{% extends 'APYDataGridBundle::blocks.html.twig' %}
+
+{% extends '@APYDataGrid/blocks.html.twig' %}
{% block grid_column_type_boolean_cell %}
@@ -52,12 +52,12 @@ grid(grid, 'MyProjectMyBundle::my_grid_template.html.twig', '', {'imgDir': 'img/
#### Use the SearchOnclick functionality with the previous block
```janjo
-grid(grid, 'MyProjectMyBundle::my_grid_template.html.twig', '', {'imgDir': 'img/'})
+grid(grid, 'my_grid_template.html.twig', '', {'imgDir': 'img/'})
```
```janjo
-
-{% extends 'APYDataGridBundle::blocks.html.twig' %}
+
+{% extends '@APYDataGrid/blocks.html.twig' %}
{% block grid_column_type_boolean_cell %}
{% set value = '' %}
diff --git a/Resources/doc/template/render_the_grid.md b/Resources/doc/template/index.md
similarity index 62%
rename from Resources/doc/template/render_the_grid.md
rename to Resources/doc/template/index.md
index 69466a87..8069a350 100644
--- a/Resources/doc/template/render_the_grid.md
+++ b/Resources/doc/template/index.md
@@ -1,5 +1,4 @@
-Render the grid
-================
+# Display the Grid (Twig template)
## Usage
@@ -8,24 +7,30 @@ Twig variable ```grid```.
```php
get('grid');
-
-$grid->setSource($source);
-
-return $grid->getGridResponse('MyProjectMyBundle::my_grid.html.twig');
-...
+class DefaultController extends Controller
+{
+ public function myGridAction()
+ {
+ // [...]
+ $grid = $this->get('grid');
+
+ $grid->setSource($source);
+
+ return $grid->getGridResponse('MyProjectMyBundle::my_grid.html.twig');
+ }
+ // [...]
+}
```
-And the template
+And the Twig template
-```janjo
+```djanjo
{{ grid(grid, theme, id, params) }}
```
-## grid function parameters
+## Grid Function Parameters Reference
|parameter|Type|Default value|Description|
|:--:|:--|:--|:--|:--|
@@ -34,16 +39,7 @@ And the template
|id|string|_none_|Set the identifier of the grid.|
|params|array|array()|Additional parameters passed to each block.|
-## Example
-
-```janjo
-
-
-{{ grid(grid) }}
-...
-```
-
-## Override the getGridResponse function
+## Overriding the getGridResponse function
See [Grid Response helper](../grid_configuration/grid_response.md) for a detailed outline of ```getGridResponse```.
@@ -66,3 +62,12 @@ if ($grid->isReadyForRedirect()) {
```
**Note:** GridResponse parameters are useless in this case and exports are managed directly in the getGridResponse function.
+
+## Learn more about advanced features and usages
+
+* [Display an ajax grid](render_an_ajax_grid.md)
+* [Cell rendering](cell_rendering.md)
+* [Filter rendering](filter_rendering.md)
+* [Overriding internal blocks](overriding_internal_blocks.md)
+* [Display an external filters box](render_external_filters.md)
+* [Display a pagerfanta pager](render_pagerfanta_pager.md)
\ No newline at end of file
diff --git a/Resources/doc/template/overriding_internal_blocks.md b/Resources/doc/template/overriding_internal_blocks.md
index f6020330..2ff70dae 100644
--- a/Resources/doc/template/overriding_internal_blocks.md
+++ b/Resources/doc/template/overriding_internal_blocks.md
@@ -6,8 +6,8 @@ Overriding internal blocks
If you want to override blocks of the grid you can use a extended template of the grid template.
```twig
-
-{% extends 'APYDataGridBundle::blocks.html.twig' %}
+
+{% extends '@APYDataGrid/blocks.html.twig' %}
{% block grid_pager %}{% endblock %}
@@ -19,25 +19,25 @@ If you want to override blocks of the grid you can use a extended template of th
This template can then be passed to the grid twig function as second parameter
```twig
-
-{{ grid(data, 'MyProjectMyBundle::my_page_grid.html.twig') }}
+
+{{ grid(data, 'my_page_grid.html.twig') }}
```
You can also apply the template globaly to your whole app by specifing it in your config.
```yaml
apy_data_grid:
- theme: 'MyProjectMyBundle::my_page_grid.html.twig'
+ theme: 'my_page_grid.html.twig'
```
## _self template
If you want to override blocks inside the current template you can use the `_self` parameter in grid template definition.
-Current template will automatically extended from the base block template (APYDataGridBundle::blocks.html.twig)
+Current template will automatically extended from the base block template (@APYDataGrid/blocks.html.twig)
```twig
-
-{% extends 'MyProjectMyBundle::layout.html.twig' %}
+
+{% extends 'layout.html.twig' %}
{% block content %}
{{ grid(grid, _self) }}
diff --git a/Resources/doc/template/render_an_ajax_grid.md b/Resources/doc/template/render_an_ajax_grid.md
index 9dd0115f..b312cef6 100644
--- a/Resources/doc/template/render_an_ajax_grid.md
+++ b/Resources/doc/template/render_an_ajax_grid.md
@@ -2,21 +2,21 @@ Render an ajax grid
===================
You can load the grid with ajax interactions.
-Simply call or extend the template `APYDataGridBundle::blocks_js.jquery.html.twig` instead of `APYDataGridBundle::blocks.html.twig`.
+Simply call or extend the template `@APYDataGrid/blocks_js.jquery.html.twig` instead of `@APYDataGrid/blocks.html.twig`.
This template only works with the jQuery Javascript Framework but you can change it to manage this feature with your own Javascript Framework.
## Usage
-Before : `{{ grid(data, 'APYDataGridBundle::blocks.html.twig') }}`
-After: `{{ grid(data, 'APYDataGridBundle::blocks_js.jquery.html.twig') }}`
+Before : `{{ grid(data, '@APYDataGrid/blocks.html.twig') }}`
+After: `{{ grid(data, '@APYDataGrid/blocks_js.jquery.html.twig') }}`
**Note**: The grid_search twig function doesn't need to extend this same template because its script are already included in the grid template.
#### Example
```django
-{{ grid_search(data, 'APYDataGridBundle::blocks.html.twig') }}
+{{ grid_search(data, '@APYDataGrid/blocks.html.twig') }}
-{{ grid(data, 'APYDataGridBundle::blocks_js.jquery.html.twig') }}
+{{ grid(data, '@APYDataGrid/blocks_js.jquery.html.twig') }}
```
\ No newline at end of file
diff --git a/Resources/doc/template/render_external_filters.md b/Resources/doc/template/render_external_filters.md
index 1aef918a..799b5089 100644
--- a/Resources/doc/template/render_external_filters.md
+++ b/Resources/doc/template/render_external_filters.md
@@ -10,14 +10,14 @@ Pass the $grid object to the view and call your grid render in your template.
...
$grid = $this->get('grid');
-return $grid->getGridResponse('MyProjectMyBundle::my_grid.html.twig');
+return $grid->getGridResponse('grid.html.twig');
...
```
And the template
```janjo
-
+
{{ grid_search(grid, theme, id, params) }}
...
@@ -29,7 +29,7 @@ And the template
|parameter|Type|Default value|Description|
|:--:|:--|:--|:--|:--|
|grid|APY/DataGridBundle/Grid/Grid||The grid object|
-|theme|string|APYDataGridBundle::blocks.html.twig|Template used to render the filters blocks|
+|theme|string|@APYDataGrid/blocks.html.twig|Template used to render the filters blocks|
|id|string|_none_|Set the identifier of the grid.|
|params|array|array()|Additional parameters passed to each block.|
@@ -38,7 +38,7 @@ And the template
#### Example
```janjo
-
+
{{ grid_search(grid) }}
@@ -52,9 +52,9 @@ And the template
If you don't want to show the filter in the grid columns, you can disable the grid_filters blocks with an external template.
-`{{ grid(grid, 'MyProjectMyBundle::grid.html.twig') }}`
+`{{ grid(grid, 'grid.html.twig') }}`
-And in your MyProjectMyBundle::grid.html.twig template
+And in your `grid.html.twig` template
```janjo
{% block grid_filters %}{% endblock %}
diff --git a/Resources/translations/messages.cs.xliff b/Resources/translations/messages.cs.xliff
index bb794633..a81e39cc 100644
--- a/Resources/translations/messages.cs.xliff
+++ b/Resources/translations/messages.cs.xliff
@@ -2,6 +2,54 @@
+
+ Page
+ strana
+
+
+ , Display
+ , zobraz
+
+
+ of %count%
+ z %count%
+
+
+ Items per page
+ položek na stranu
+
+
+ Select visible
+ Označ viditelné
+
+
+ Select all
+ Označ všechno
+
+
+ Deselect visible
+ Odznač viditelné
+
+
+ Deselect all
+ Odznač všechno
+
+
+ Action
+ Akce
+
+
+ Submit Action
+ Odeslat
+
+
+ From:
+ Od:
+
+
+ To:
+ Do:
+ eqRovná se
@@ -64,8 +112,52 @@
%count% Results,
- %count% Výsledek, |%count% Výsledků,
+ %count% výsledek, |%count% výsledky, |%count% výsledků,
+
+
+ Search
+ Hledat
+
+
+ Reset
+ Resetovat
+
+
+ Order by
+ Řadit dle
+
+
+ slike
+ Obsahuje
+
+
+ nslike
+ Neobsahuje
+
+
+ rslike
+ Začíná na
+
+
+ lslike
+ Končí na
+
+
+ No data
+ Žádná data
+
+
+ No result
+ Žádné výsledky
+
+
+ Selected _s_ rows
+ Označeno _s_ řádků
+
+
+ Actions
+ Akce
-
\ No newline at end of file
+
diff --git a/Resources/translations/messages.en.xliff b/Resources/translations/messages.en.xliff
index 11ba3946..33ab8486 100644
--- a/Resources/translations/messages.en.xliff
+++ b/Resources/translations/messages.en.xliff
@@ -2,6 +2,46 @@
+
+ Page
+ Page
+
+
+ , Display
+ , Display
+
+
+ of %count%
+ of %count%
+
+
+ Items per page
+ Items per page
+
+
+ Select visible
+ Select visible
+
+
+ Select all
+ Select all
+
+
+ Deselect visible
+ Deselect visible
+
+
+ Deselect all
+ Deselect all
+
+
+ Action
+ Action
+
+
+ Submit Action
+ Submit Action
+ eqEquals
@@ -66,6 +106,18 @@
%count% Results, %count% Result, |%count% Results,
+
+ Search
+ Search
+
+
+ Reset
+ Reset
+
+
+ Order by
+ Order by
+
@@ -138,6 +190,22 @@
lslikeEnds with
+
+ No data
+ No data
+
+
+ No result
+ No result
+
+
+ Selected _s_ rows
+ Selected _s_ rows
+
+
+ Actions
+ Actions
+
-
\ No newline at end of file
+
diff --git a/Resources/translations/messages.pl.xliff b/Resources/translations/messages.pl.xliff
index 2be9d822..0c3ff253 100644
--- a/Resources/translations/messages.pl.xliff
+++ b/Resources/translations/messages.pl.xliff
@@ -64,7 +64,7 @@
%count% Results,
- %count% Wynik, |%count% Wyników,
+ {0} %count% Wyników|{1} %count% Wynik|]1,Inf[ %count% Wyników,
diff --git a/Resources/views/blocks.html.twig b/Resources/views/blocks.html.twig
index e9230061..466ceac6 100644
--- a/Resources/views/blocks.html.twig
+++ b/Resources/views/blocks.html.twig
@@ -1,7 +1,7 @@
{# ------------------------------------------------------ grid ------------------------------------------------------ #}
{% block grid %}
-{% if grid.totalCount > 0 or grid.isFiltered or grid.noDataMessage is sameas(false) %}
+{% if grid.totalCount > 0 or grid.isFiltered or grid.noDataMessage is same as (false) %}