Skip to content

Commit

Permalink
Improved Templateable Models + Template Properties
Browse files Browse the repository at this point in the history
Related to locomotivemtl/charcoal-property#39ecc3e

Changes:
- `TemplateProperty`: Revised use of available templates based
- `TemplateOptionsProperty`: Revised `TemplateProperty` usage
- `TemplateableTrait`: Ignore numbers as template options values
- Completed unit tests for the affected properties and mixins
- Updated `phpunit.xml` to test `Admin` and `Property` namespaces
  • Loading branch information
mcaskill committed May 25, 2017
1 parent fcbecbd commit 2797cb9
Show file tree
Hide file tree
Showing 8 changed files with 524 additions and 24 deletions.
6 changes: 4 additions & 2 deletions src/Charcoal/Cms/TemplateableTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,9 @@ public function controllerIdent()
*/
public function setTemplateOptions($options)
{
if (is_string($options)) {
if (is_numeric($options)) {
$options = null;
} elseif (is_string($options)) {
$options = json_decode($options, true);
}

Expand All @@ -95,7 +97,7 @@ public function setTemplateOptions($options)
/**
* Retrieve the template's customized options.
*
* @return array
* @return mixed
*/
public function templateOptions()
{
Expand Down
11 changes: 3 additions & 8 deletions src/Charcoal/Property/TemplateOptionsProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
use InvalidArgumentException;

// From 'charcoal-property'
use Charcoal\Property\PropertyInterface;
use Charcoal\Property\StructureProperty;
use Charcoal\Property\TemplateProperty;

Expand Down Expand Up @@ -35,14 +34,10 @@ public function type()
public function addStructureInterface($interface)
{
if ($interface instanceof TemplateProperty) {
$choice = $interface->choice($interface->val());
if (isset($choice['controller'])) {
$interface = $choice['controller'];
} elseif (isset($choice['template'])) {
$interface = $choice['template'];
} else {
$interface = (string)$interface;
if (empty($interface)) {
throw new InvalidArgumentException(
'Template structure interface invalid'
'Invalid template structure interface'
);
}
}
Expand Down
150 changes: 137 additions & 13 deletions src/Charcoal/Property/TemplateProperty.php
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
// From Pimple
use Pimple\Container;

// From 'charcoal-translator'
use Charcoal\Translator\Translation;

// From 'charcoal-property'
use Charcoal\Property\AbstractProperty;
use Charcoal\Property\SelectablePropertyInterface;
Expand All @@ -22,6 +25,21 @@ class TemplateProperty extends AbstractProperty implements SelectablePropertyInt
{
use SelectablePropertyTrait;

/**
* The available selectable templates.
*
* @var array|null
*/
private $availableTemplates;

/**
* @return string
*/
public function type()
{
return 'template';
}

/**
* Inject dependencies from a DI Container.
*
Expand All @@ -32,32 +50,141 @@ public function setDependencies(Container $container)
{
parent::setDependencies($container);

$this->setChoices($container['config']['templates']);
if (isset($container['config']['templates'])) {
$this->availableTemplates = $this->parseChoices($container['config']['templates']);
$this->choices = $this->availableTemplates;
}
}

/**
* Set the available choices.
*
* @param array $choices One or more choice structures.
* @return TemplateProperty Chainable.
*/
public function setChoices(array $choices)
{
unset($choices);

$this->logger->debug(
'Choices can not be set for template properties. They are auto-generated from available languages.'
);

return $this;
}

/**
* Merge the available choices.
*
* @param array $choices One or more choice structures.
* @return TemplateProperty Chainable.
*/
public function addChoices(array $choices)
{
unset($choices);

$this->logger->debug(
'Choices can not be added for template properties. They are auto-generated from available languages.'
);

return $this;
}

/**
* Add a choice to the available choices.
*
* @param string $choiceIdent The choice identifier (will be key / default ident).
* @param string|array $choice A string representing the choice label or a structure.
* @return TemplateProperty Chainable.
*/
public function addChoice($choiceIdent, $choice)
{
unset($choiceIdent, $choice);

$this->logger->debug(
'Choices can not be added for template properties. They are auto-generated from available languages.'
);

return $this;
}

/**
* Format the given value for display.
*
* @param mixed $val The value to to convert for display.
* @param array $options Optional display options.
* @return string
*/
public function type()
public function displayVal($val, array $options = [])
{
return 'template';
if ($val === null || $val === '') {
return '';
}

/** Parse multilingual values */
if ($this->l10n()) {
$propertyValue = $this->l10nVal($val, $options);
if ($propertyValue === null) {
return '';
}
} elseif ($val instanceof Translation) {
$propertyValue = (string)$val;
} else {
$propertyValue = $val;
}

$separator = $this->multipleSeparator();

/** Parse multiple values / ensure they are of array type. */
if ($this->multiple()) {
if (!is_array($propertyValue)) {
$propertyValue = explode($separator, $propertyValue);
}
}

if ($separator === ',') {
$separator = ', ';
}

if (is_array($propertyValue)) {
foreach ($propertyValue as &$value) {
if (is_string($value)) {
$value = $this->choiceLabel($value);
if (!is_string($value)) {
$value = $this->l10nVal($value, $options);
}
}
}
$propertyValue = implode($separator, $propertyValue);
} elseif (is_string($propertyValue)) {
$propertyValue = $this->choiceLabel($propertyValue);
if (!is_string($propertyValue)) {
$propertyValue = $this->l10nVal($propertyValue, $options);
}
}

return $propertyValue;
}

/**
* Retrieve the selected template's fully-qualified class name.
* Retrieve the selected template's FQCN.
*
* @return string|null
* @return string
*/
public function __toString()
{
$val = $this->val();
$tpl = $this->choice($val);

if (isset($tpl['class'])) {
return $tpl['class'];
if ($this->hasChoice($val)) {
$choice = $this->choice($val);
$keys = [ 'controller', 'template', 'class' ];
foreach ($keys as $key) {
if (isset($choice[$key])) {
return $choice[$key];
}
}
}

return null;
return '';
}

/**
Expand All @@ -71,13 +198,10 @@ public function sqlExtra()
/**
* Get the SQL type (Storage format)
*
* Stored as `VARCHAR` for maxLength under 255 and `TEXT` for other, longer strings
*
* @return string The SQL type
*/
public function sqlType()
{
// Multiple strings are always stored as TEXT because they can hold multiple values
if ($this->multiple()) {
return 'TEXT';
}
Expand Down
58 changes: 58 additions & 0 deletions tests/Charcoal/Cms/ContainerProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,64 @@ public function registerTranslator(Container $container)
};
}

/**
* Setup the application's translator service.
*
* @param Container $container A DI container.
* @return void
*/
public function registerMultilingualTranslator(Container $container)
{
$container['locales/manager'] = function (Container $container) {
$manager = new LocalesManager([
'locales' => [
'en' => [
'locale' => 'en-US',
'name' => [
'en' => 'English',
'fr' => 'Anglais',
'es' => 'Inglés'
]
],
'fr' => [
'locale' => 'fr-CA',
'name' => [
'en' => 'French',
'fr' => 'Français',
'es' => 'Francés'
]
],
'de' => [
'locale' => 'de-DE'
],
'es' => [
'locale' => 'es-MX'
]
],
'default_language' => 'en',
'fallback_languages' => [ 'en' ]
]);

$manager->setCurrentLocale($manager->currentLocale());

return $manager;
};

$container['translator'] = function (Container $container) {
$translator = new Translator([
'manager' => $container['locales/manager']
]);

$translator->addLoader('array', new ArrayLoader());
$translator->addResource('array', [ 'locale.de' => 'German' ], 'en', 'messages');
$translator->addResource('array', [ 'locale.de' => 'Allemand' ], 'fr', 'messages');
$translator->addResource('array', [ 'locale.de' => 'Deutsch' ], 'es', 'messages');
$translator->addResource('array', [ 'locale.de' => 'Alemán' ], 'de', 'messages');

return $translator;
};
}

public function registerMetadataLoader(Container $container)
{
$container['metadata/loader'] = function (Container $container) {
Expand Down
72 changes: 72 additions & 0 deletions tests/Charcoal/Cms/TemplateableTraitTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
<?php

namespace Charcoal\Tests\Property;

use InvalidArgumentException;

// From 'charcoal-property'
use Charcoal\Cms\TemplateableTrait;

/**
* Template Property Test
*/
class TemplateableTraitTest extends \PHPUnit_Framework_TestCase
{
use \Charcoal\Tests\Cms\ContainerIntegrationTrait;

/**
* Tested Class.
*
* @var TemplateableTrait
*/
public $obj;

/**
* Set up the test.
*/
public function setUp()
{
$this->obj = $this->getMockForTrait(TemplateableTrait::class);
}

public function testTemplateIdent()
{
$this->assertNull($this->obj->templateIdent());

$this->obj->setTemplateIdent('foobar');
$this->assertEquals('foobar', $this->obj->templateIdent());
}

public function testControllerIdent()
{
$this->assertNull($this->obj->controllerIdent());

$this->obj->setControllerIdent('foobar');
$this->assertEquals('foobar', $this->obj->controllerIdent());
}

public function testTemplateOptions()
{
$this->assertInternalType('array', $this->obj->templateOptions());
$this->assertEmpty($this->obj->templateOptions());

$this->obj->setTemplateOptions(false);
$this->assertFalse($this->obj->templateOptions());

$this->obj->setTemplateOptions(42);
$this->assertNull($this->obj->templateOptions());

$this->obj->setTemplateOptions('foobar');
$this->assertNull($this->obj->templateOptions());

$this->obj->setTemplateOptions('{"foo":"bar"}');
$this->assertEquals([ 'foo' => 'bar' ], $this->obj->templateOptions());

$this->obj->setTemplateOptions([ 'foo' => 'bar' ]);
$this->assertEquals([ 'foo' => 'bar' ], $this->obj->templateOptions());

$obj = new \stdClass();
$this->obj->setTemplateOptions($obj);
$this->assertEquals($obj, $this->obj->templateOptions());
}
}

0 comments on commit 2797cb9

Please sign in to comment.