Your model has a list of accepted values. Say, your student score can be low, medium, or high. You want to store these values as Integers in the database and as a programmer, you want to work with constants like so:
Score::MEDIUM
Also, your HTML <select>
field should have options for all available Constant values and label them with a translated label from your language file.
How do you glue all of this together?
My other gist shows a basic value object
But for this task, I extended ValueObject
and call it TypeObject
:
/**
* Representation of a value object that accepts a range of predefined
* Constants and labels their numeric representation with a translated string
*
* A TypeObject should use one or more Constants that are treated as the set of accepted values.
* Each Constant is mapped to a string representation, but the string representation works
* with keys for language files. This way, TypeObject can be used with different languages.
*
* @package Demo
*/
abstract class TypeObject extends ValueObject {
/**
* @var array Constant => Laravel string key for a language file
*/
protected static $typeLabels = [];
/**
* @param mixed $value
* @return string Translated string (uses Laravel's trans() method)
*/
public static function label($value) {
return isset(static::$typeLabels[$value]) ? trans(static::$typeLabels[$value]) : '';
}
/**
* Returns an array of all labels for all constants
*
* @return array
*/
public static function labels() {
$translatedLabels = array();
foreach(static::$typeLabels as $key => $label) {
$translatedLabels[$key] = trans($label);
}
return $translatedLabels;
}
/**
* Returns an array of all accepted constant values
*
* @return array
*/
public static function values() {
return array_keys(static::$typeLabels);
}
/**
* Checks if $value is defined by a constant
*
* @param mixed $value
* @throws \InvalidArgumentException if value validation fails
*/
protected function validateValue($value) {
if (!in_array($value, $this->values())) {
throw new \InvalidArgumentException("Invalid value [$value] for " . static::class);
}
}
}
A value object now can extend TypeObject
like so:
class Score extends TypeObject {
const LOW = 1;
const MEDIUM = 2;
const HIGH = 3;
protected static $typeLabels = [
self::LOW => 'typelabels.student_score_low',
self::MEDIUM => 'typelabels.student_score_medium',
self::HIGH => 'typelabels.student_score_high',
];
}
The model uses TypeObject
just like ValueObject
in my other gist (see above).
And the model can be used like this:
$student = new Student;
$student->name = 'John Smith';
$student->email = new EmailAddress('[email protected]');
$student->score = new Score(Score::MEDIUM);
$student->save();
See how you can work comfortablly with Constant values?
In your view, you can just do this:
{!! Form::select('score', Demo\Score::labels(), $student->score) !!}
This creates a nice dropdown and all options use the correct Constant values and map them to their translated labels: