diff --git a/forms/Datagrid.php b/forms/Datagrid.php index 76f23759c..e1ea0fdda 100644 --- a/forms/Datagrid.php +++ b/forms/Datagrid.php @@ -1,7 +1,8 @@ setDatasource($source); - if ($dataPresenterClassName) $this->dataPresenterClassName = $dataPresenterClassName; - $this->setDataPresenter($this->dataPresenterClassName); + if ($datasource) $this->setDatasource($datasource); + if ($dataPresenterClassName) $this->setDataPresenter($dataPresenterClassName); } - function setItemClass($itemClass){ - $this->itemClass = $itemClass; - } - - function setDataclass($dataClass){ + /** + * + * @param string $dataClass + */ + function setDataclass($dataClass) { $this->dataClass = $dataClass; } - function setDataPresenter($dataPresenterClassName){ - $this->dataPresenter = $dataPresenterClassName; + /** + * + * @param string $dataPresenterClassName + * @throws Exception + */ + function setDataPresenter($dataPresenterClassName) { + if(!$dataPresenterClassName){ + throw new Exception('Datapresenter for Datagrid must be set with a class'); + } + if(!class_exists($dataPresenterClassName)){ + throw new Exception('Datapresenter for Datagrid must be set with an existing class'); + } + + if($dataPresenterClassName !='DatagridPresenter' && !ClassInfo::is_subclass_of($dataPresenterClassName, 'DatagridPresenter')){ + throw new Exception('Datapresenter "$dataPresenterClassName" must inherit DatagridPresenter' ); + } + $this->dataPresenterClassName = $dataPresenterClassName; } - function getDataclass(){ + /** + * + * @return type + */ + function getDataclass() { if ($this->dataClass) return $this->dataClass; if ($this->datasource->dataClass) return $this->datasource->dataClass; - throw new Exception(); + throw new Exception(get_class($this).' does not have a dataclass'); } /** @@ -56,9 +87,11 @@ class Datagrid extends FormField { * * @param SS_List $datasource */ - public function setDatasource(SS_List $datasource ) { + public function setDatasource(SS_List $datasource) { $this->datasource = $datasource; - $this->fieldList = singleton($datasource->dataClass)->summaryFields(); + if($datasource->dataClass){ + $this->fieldList = singleton($datasource->dataClass)->summaryFields(); + } } /** @@ -70,190 +103,22 @@ class Datagrid extends FormField { return $this->datasource; } + /** + * Returns the list of fields, or the 'column header' names of this grid + * + * @return array - e.g array('ID'=>'ID', 'Name'=>'Name) + */ function FieldList() { return $this->fieldList; } - + /** + * + * @return string - html for the form + */ function FieldHolder() { - $dataPresenter = new $this->dataPresenter(); + $dataPresenter = new $this->dataPresenterClassName(); $dataPresenter->setDatagrid($this); return $dataPresenter->render(); } -} - -class DatagridPresenter extends ViewableData { - - /** - * @var $template string Template-Overrides - */ - protected $template = 'DatagridPresenter'; - /** - * @var $itemClass string Class name for each item/row - */ - protected $itemClass = 'DatagridPresenter_Item'; - - protected $datagrid = null; - - public $fieldCasting = array(); - - public $fieldFormatting = array(); - - - function setTemplate($template){ - $this->template = $template; - } - - public function setDatagrid(Datagrid $datagrid){ - $this->datagrid = $datagrid; - } - - public function getDatagrid(){ - return $this->datagrid; - } - - /** - * Return a DataObjectSet of Datagrid_Item objects, suitable for display in the template. - */ - function Items() { - $fieldItems = new ArrayList(); - if($items = $this->datagrid->datasource) { - foreach($items as $item) { - if($item) $fieldItems->push(new $this->itemClass($item, $this)); - } - } - return $fieldItems; - } - - /** - * Get the headers or column names for this grid - * - * The returning array will have the format of - * array( - * 'FirstName' => 'First name', - * 'Description' => 'A nice description' - * ) - * - * @return array - */ - public function Headers() { - if($this->datagrid->datasource instanceof DataList ) { - $fieldHeaders = new ArrayList(); - $fieldHeadersSummaryFields = singleton($this->datagrid->datasource->dataClass)->summaryFields(); - if (is_array($fieldHeadersSummaryFields)){ - foreach ($fieldHeadersSummaryFields as $name=>$title){ - $fieldHeaders->push(new ArrayData(array('Name'=>$name, 'Title'=>$title))); - } - } - return $fieldHeaders; - } else { - $firstItem = $this->datasource->first(); - if(!$firstItem) { - return array(); - } - return array_combine(array_keys($firstItem),array_keys($firstItem)); - } - } - - function setFieldCasting($casting) { - $this->fieldCasting = $casting; - } - - function setFieldFormatting($formatting) { - $this->fieldFormatting = $formatting; - } - - - function render(){ - return $this->renderWith(array($this->template)); - } -} - -/** - * A single record in a Datagrid. - * @package forms - * @see Datagrid - */ -class DatagridPresenter_Item extends ViewableData { - - /** - * @var DataObject The underlying data record, - * usually an element of {@link Datagrid->datasource()}. - */ - protected $item; - - /** - * @var Datagrid - */ - protected $parent; - - function ID() { - return $this->item->ID; - } - - function Parent() { - return $this->parent; - } - - function __construct($item, $parent) { - $this->failover = $this->item = $item; - $this->parent = $parent; - parent::__construct(); - } - - function Fields($xmlSafe = true) { - $list = $this->parent->getDatagrid()->FieldList(); - foreach($list as $fieldName => $fieldTitle) { - $value = ""; - - // TODO Delegates that to DataList - // This supports simple FieldName syntax - if(strpos($fieldName,'.') === false) { - $value = ($this->item->XML_val($fieldName) && $xmlSafe) ? $this->item->XML_val($fieldName) : $this->item->RAW_val($fieldName); - // This support the syntax fieldName = Relation.RelatedField - } else { - $fieldNameParts = explode('.', $fieldName) ; - $tmpItem = $this->item; - for($j=0;$j$relationMethod; - } else { - if($tmpItem) $tmpItem = $tmpItem->$relationMethod(); - } - } - } - - // casting - if(array_key_exists($fieldName, $this->parent->fieldCasting)) { - $value = $this->parent->getCastedValue($value, $this->parent->fieldCasting[$fieldName]); - } elseif(is_object($value) && method_exists($value, 'Nice')) { - $value = $value->Nice(); - } - - // formatting - $item = $this->item; - if(array_key_exists($fieldName, $this->parent->fieldFormatting)) { - $format = str_replace('$value', "__VAL__", $this->parent->fieldFormatting[$fieldName]); - $format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format); - $format = str_replace('__VAL__', '$value', $format); - eval('$value = "' . $format . '";'); - } - - //escape - if($escape = $this->parent->getDatagrid()->fieldEscape){ - foreach($escape as $search => $replace){ - $value = str_replace($search, $replace, $value); - } - } - - $fields[] = new ArrayData(array( - "Name" => $fieldName, - "Title" => $fieldTitle, - "Value" => $value - )); - } - return new ArrayList($fields); - } -} +} \ No newline at end of file diff --git a/forms/DatagridPresenter.php b/forms/DatagridPresenter.php new file mode 100644 index 000000000..aeb4d049b --- /dev/null +++ b/forms/DatagridPresenter.php @@ -0,0 +1,254 @@ +template = $template; + } + + /** + * + * @param Datagrid $datagrid + */ + public function setDatagrid(Datagrid $datagrid){ + $this->datagrid = $datagrid; + } + + /** + * + * @return Datagrid + */ + public function getDatagrid(){ + return $this->datagrid; + } + + /** + * Return a ArrayList of Datagrid_Item objects, suitable for display in the template. + * + * @return ArrayList + */ + function Items() { + $fieldItems = new ArrayList(); + if($items = $this->datagrid->datasource) { + foreach($items as $item) { + if(!$item) { + continue; + } + $fieldItems->push(new $this->itemClass($item, $this)); + } + } + return $fieldItems; + } + + /** + * Get the headers or column names for this grid + * + * The returning array will have the format of + * array( + * 'FirstName' => 'First name', + * 'Description' => 'A nice description' + * ) + * + * @return ArrayList + */ + public function Headers() { + if($this->datagrid->datasource instanceof DataList ) { + return $this->getHeadersFromDatalist(); + } else { + if(!$this->datasource) { + return array(); + } + $firstItem = $this->datasource->first(); + if(!$firstItem) { + return array(); + } + return array_combine(array_keys($firstItem),array_keys($firstItem)); + } + } + + /** + * + * @return ArrayList + */ + protected function getHeadersFromDatalist(){ + $fieldHeaders = new ArrayList(); + $fieldHeadersSummaryFields = singleton($this->datagrid->datasource->dataClass)->summaryFields(); + if (is_array($fieldHeadersSummaryFields)){ + foreach ($fieldHeadersSummaryFields as $name=>$title){ + $fieldHeaders->push(new ArrayData(array('Name'=>$name, 'Title'=>$title))); + } + } + return $fieldHeaders; + } + + /** + * + * @param type $casting + */ + function setFieldCasting($casting) { + $this->fieldCasting = $casting; + } + + /** + * + * @param type $formatting + */ + function setFieldFormatting($formatting) { + $this->fieldFormatting = $formatting; + } + + /** + * + * @return string - html + */ + function render(){ + return $this->renderWith(array($this->template)); + } +} + +/** + * A single record in a Datagrid. + * @package forms + * @see Datagrid + */ +class DatagridPresenter_Item extends ViewableData { + + /** + * @var DataObject The underlying data record, + * usually an element of {@link Datagrid->datasource()}. + */ + protected $item; + + /** + * @var Datagrid + */ + protected $parent; + + /** + * + * @param type $item + * @param type $parent + */ + public function __construct($item, $parent) { + $this->failover = $this->item = $item; + $this->parent = $parent; + parent::__construct(); + } + + /** + * + * @return int + */ + public function ID() { + return $this->item->ID; + } + + /** + * + * @return type + */ + public function Parent() { + return $this->parent; + } + + /** + * + * @param bool $xmlSafe + * @return ArrayList + */ + public function Fields($xmlSafe = true) { + $list = $this->parent->getDatagrid()->FieldList(); + foreach($list as $fieldName => $fieldTitle) { + $value = ""; + + // TODO Delegates that to DataList + // This supports simple FieldName syntax + if(strpos($fieldName,'.') === false) { + $value = ($this->item->XML_val($fieldName) && $xmlSafe) ? $this->item->XML_val($fieldName) : $this->item->RAW_val($fieldName); + // This support the syntax fieldName = Relation.RelatedField + } else { + $fieldNameParts = explode('.', $fieldName) ; + $tmpItem = $this->item; + for($j=0;$j$relationMethod; + } else { + if($tmpItem) $tmpItem = $tmpItem->$relationMethod(); + } + } + } + + // casting + if(array_key_exists($fieldName, $this->parent->fieldCasting)) { + $value = $this->parent->getCastedValue($value, $this->parent->fieldCasting[$fieldName]); + } elseif(is_object($value) && method_exists($value, 'Nice')) { + $value = $value->Nice(); + } + + // formatting + $item = $this->item; + if(array_key_exists($fieldName, $this->parent->fieldFormatting)) { + $format = str_replace('$value', "__VAL__", $this->parent->fieldFormatting[$fieldName]); + $format = preg_replace('/\$([A-Za-z0-9-_]+)/','$item->$1', $format); + $format = str_replace('__VAL__', '$value', $format); + eval('$value = "' . $format . '";'); + } + + //escape + if($escape = $this->parent->getDatagrid()->fieldEscape){ + foreach($escape as $search => $replace){ + $value = str_replace($search, $replace, $value); + } + } + + $fields[] = new ArrayData(array( + "Name" => $fieldName, + "Title" => $fieldTitle, + "Value" => $value + )); + } + return new ArrayList($fields); + } +} diff --git a/tests/forms/DatagridFunctionalTest.php b/tests/forms/DatagridFunctionalTest.php index 4acb71c50..86729225b 100644 --- a/tests/forms/DatagridFunctionalTest.php +++ b/tests/forms/DatagridFunctionalTest.php @@ -20,10 +20,6 @@ class DatagridFunctionalTest extends FunctionalTest { 'DatagridTest_Person', ); - public function testGetInstance() { - $this->assertTrue(new Datagrid('testgrid') instanceof Datagrid, 'Trying to find an instance of Datagrid.'); - } - public function testAddToForm() { $firstPerson = $this->objFromFixture('DatagridTest_Person', 'first'); $response = $this->get("DatagridFunctionalTest_Controller/"); diff --git a/tests/forms/DatagridPresenterTest.php b/tests/forms/DatagridPresenterTest.php new file mode 100644 index 000000000..7fe55d732 --- /dev/null +++ b/tests/forms/DatagridPresenterTest.php @@ -0,0 +1,44 @@ +assertTrue(new DatagridPresenter instanceof DatagridPresenter, 'Trying to find an instance of DatagridPresenter'); + } + + public function testHeaders() { + $presenter = new DatagridPresenter(); + $grid = new Datagrid('testgrid', 'testgrid', new DataList('DatagridTest_Person')); + $presenter->setDatagrid($grid); + $headers = $presenter->Headers()->first(); + + $this->assertEquals(1, count($headers)); + $this->assertEquals('Name', $headers->Name ); + } + + public function testItemsReturnCorrectNumberOfItems() { + $presenter = new DatagridPresenter(); + $grid = new Datagrid('testgrid', 'testgrid', new DataList('DatagridTest_Person')); + $presenter->setDatagrid($grid); + $this->assertEquals(2, $presenter->Items()->count()); + } + +} \ No newline at end of file diff --git a/tests/forms/DatagridTest.php b/tests/forms/DatagridTest.php index 1fbaebab0..f7ec8d950 100644 --- a/tests/forms/DatagridTest.php +++ b/tests/forms/DatagridTest.php @@ -23,33 +23,57 @@ class DatagridTest extends SapphireTest { public function testGetInstance() { $this->assertTrue(new Datagrid('Testgrid') instanceof FormField, 'Datagrid should be a FormField'); } - + public function testSetDataSource() { $grid = new Datagrid('Testgrid'); $source = new ArrayList(); - $grid->setDatasource( $source ); + $grid->setDatasource($source); $this->assertEquals($source, $grid->getDatasource()); } - - public function testGetDefaultHeadersFromEmptyArrayList() { + + function testSetEmptyDataPresenter() { + $this->setExpectedException('Exception'); $grid = new Datagrid('Testgrid'); - $source = new ArrayList(); - $grid->setDatasource($source); - $this->assertEquals(array(), $grid->getHeaders()); + $grid->setDataPresenter(''); } - - public function testGetDefaultHeadersFromArrayList() { + + function testSetNonExistingDataPresenter() { + $this->setExpectedException('Exception'); $grid = new Datagrid('Testgrid'); - $source = new ArrayList(array(array('ID'=>1,'Name'=>'Aaron Aardwark'))); - $grid->setDatasource($source); - $this->assertEquals(array('ID'=>'ID','Name'=>'Name'), $grid->getHeaders()); + $grid->setDataPresenter('ifThisClassExistsIWouldBeSurprised'); } - - public function testGetDefaultHeadersFromDataList() { + + function testSetDataPresenterWithDataObject() { + $this->setExpectedException('Exception'); $grid = new Datagrid('Testgrid'); - $source = new DataList('DatagridTest_Person'); - $grid->setDatasource($source); - $this->assertEquals(array('Name'=>'Name','ID'=>'ID'), $grid->getHeaders()); + $grid->setDataPresenter('DataObject'); + } + + function testSetDataPresenter() { + $grid = new Datagrid('Testgrid'); + $grid->setDataPresenter('DatagridPresenter'); + } + + function testFieldListIsNullWithoutDataSource() { + $grid = new Datagrid('Testgrid'); + $this->assertNull($grid->FieldList()); + } + + function testFieldList() { + $grid = new Datagrid('Testgrid'); + $grid->setDatasource(new DataList('DatagridTest_Person')); + $this->assertNotNull($grid->FieldList()); + $this->assertEquals(array('Name'=>'Name','ID'=>'ID'), $grid->FieldList()); + } + + /** + * This is better tested in the DatagridFunctionalTest + * + * @see DatagridFunctionalTest + */ + function testFieldHolder() { + $grid = new Datagrid('Testgrid'); + $this->assertNotNull($grid->FieldHolder()); } } diff --git a/tests/forms/DatagridTest.yml b/tests/forms/DatagridTest.yml index d9ead4ba2..bc8493604 100644 --- a/tests/forms/DatagridTest.yml +++ b/tests/forms/DatagridTest.yml @@ -1,3 +1,5 @@ DatagridTest_Person: first: - Name: First Person \ No newline at end of file + Name: First Person + second: + Name: Second Person \ No newline at end of file diff --git a/tests/javascript/bananas/bananas.html b/tests/javascript/bananas/bananas.html new file mode 100644 index 000000000..398ae68f2 --- /dev/null +++ b/tests/javascript/bananas/bananas.html @@ -0,0 +1,44 @@ + + + + Test of Banana javascript + + + + + + + + + + + + diff --git a/tests/javascript/bananas/bananas.js b/tests/javascript/bananas/bananas.js new file mode 100644 index 000000000..1bce7fe9a --- /dev/null +++ b/tests/javascript/bananas/bananas.js @@ -0,0 +1,16 @@ +Banana = { + getAmount: function() { + return 2; + }, + getColor: function() { + return 'brown'; + } +} +describe("The banana", function() { + it("should have two left", function() { + expect(Banana.getAmount()).toEqual(2); + }); + it("should be yellow", function() { + expect(Banana.getColor()).toEqual('yellow'); + }); +}); \ No newline at end of file