1: <?php
2:
3: namespace Charcoal\Model;
4:
5: use \Exception;
6: use \InvalidArgumentException;
7:
8: // Local module (`charcoal-core`) dependencies
9: use \Charcoal\Model\MetadataInterface;
10: use \Charcoal\Model\Service\MetadataLoader;
11:
12: /**
13: * Default implementation, as trait, of the `DescribableInterface`.
14: */
15: trait DescribableTrait
16: {
17: /**
18: * @var MetadataLoader $metadataLoader
19: */
20: protected $metadataLoader = null;
21:
22: /**
23: * @var MetadataInterface $metadata
24: */
25: protected $metadata;
26:
27: /**
28: * @var string $metadataIdent
29: */
30: protected $metadataIdent;
31:
32: /**
33: * Describable object needs to have a `setData()` method
34: *
35: * @param array $data The object's data.
36: * @return DescribableInterface Chainable
37: */
38: abstract public function setData(array $data);
39:
40: /**
41: * @param MetadataLoader $loader The loader instance, used to load metadata.
42: * @return DescribableInterface Chainable
43: */
44: public function setMetadataLoader(MetadataLoader $loader)
45: {
46: $this->metadataLoader = $loader;
47: return $this;
48: }
49:
50: /**
51: * Safe MetdataLoader getter. Create the loader if it does not exist.
52: *
53: * @throws Exception If the metadata loader was not set.
54: * @return MetadataLoader
55: */
56: protected function metadataLoader()
57: {
58: if (!$this->metadataLoader) {
59: throw new Exception(
60: sprintf('Metadata loader was not set for "%s"', get_class($this))
61: );
62: }
63: return $this->metadataLoader;
64: }
65:
66: /**
67: * @param array|MetadataInterface $metadata The object's metadata.
68: * @throws InvalidArgumentException If the parameter is not an array or MetadataInterface.
69: * @return DescribableInterface Chainable
70: */
71: public function setMetadata($metadata)
72: {
73: if (is_array($metadata)) {
74: $meta = $this->createMetadata();
75: $meta->merge($metadata);
76: $this->metadata = $meta;
77: } elseif ($metadata instanceof MetadataInterface) {
78: $this->metadata = $metadata;
79: } else {
80: throw new InvalidArgumentException(
81: 'Metadata argument is invalid (must be array or Metadata object).'
82: );
83: }
84:
85: // Chainable
86: return $this;
87: }
88:
89: /**
90: * @return MetadataInterface
91: */
92: public function metadata()
93: {
94: if ($this->metadata === null) {
95: return $this->loadMetadata();
96: }
97: return $this->metadata;
98: }
99:
100: /**
101: * Load a metadata file and store it as a static var.
102: *
103: * Use a `MetadataLoader` object and the object's metadataIdent
104: * to load the metadata content (typically from the filesystem, as json).
105: *
106: * @param string $metadataIdent Optional ident.
107: * @return MetadataInterface
108: */
109: public function loadMetadata($metadataIdent = null)
110: {
111: if ($metadataIdent === null) {
112: $metadataIdent = $this->metadataIdent();
113: }
114:
115: $metadataLoader = $this->metadataLoader();
116: $metadata = $metadataLoader->load($metadataIdent, $this->createMetadata());
117: $this->setMetadata($metadata);
118:
119: return $metadata;
120: }
121:
122: /**
123: * @return MetadataInterface
124: */
125: abstract protected function createMetadata();
126:
127: /**
128: * @param string $metadataIdent The metadata ident.
129: * @return DescribableInterface Chainable
130: */
131: public function setMetadataIdent($metadataIdent)
132: {
133: $this->metadataIdent = $metadataIdent;
134: return $this;
135: }
136:
137: /**
138: * Get the metadata ident, or generate it from class name.
139: *
140: * @return string
141: */
142: public function metadataIdent()
143: {
144: if ($this->metadataIdent === null) {
145: $this->metadataIdent = $this->generateMetadataIdent();
146: }
147: return $this->metadataIdent;
148: }
149:
150: /**
151: * Generate a metadata ident from class name.
152: *
153: * Change `\` and `.` to `/` and force lowercase
154: *
155: * @return string
156: */
157: protected function generateMetadataIdent()
158: {
159: $classname = get_class($this);
160: $ident = preg_replace('/([a-z])([A-Z])/', '$1-$2', $classname);
161: $metadataIdent = strtolower(str_replace('\\', '/', $ident));
162: return $metadataIdent;
163: }
164: }
165: