createdAt = new \DateTime(); $this->taxonomies = new ArrayCollection(); $this->fields = new ArrayCollection(); } public function __toString(): string { $contentName = $this->getDefinition() ? $this->getContentTypeName() : 'Content'; if ($this->getId()) { return sprintf('%s #%d', $contentName, $this->getId()); } return sprintf('New %s', $contentName); } public function getId(): ?int { return $this->id; } /** * @see \Bolt\EventListener\ContentFillListener */ public function setDefinitionFromContentTypesConfig(LaravelCollection $contentTypesConfig): void { $this->contentTypeDefinition = ContentType::factory($this->contentType, $contentTypesConfig); } public function getDefinition(): ?ContentType { return $this->contentTypeDefinition; } public function getSlug(): ?string { return $this->getFieldValue('slug'); } public function getContentType(): ?string { return $this->contentType; } public function setContentType(string $contentType): void { $this->contentType = $contentType; } public function getContentTypeSlug(): string { if ($this->getDefinition() === null) { throw new \RuntimeException('Content not fully initialized'); } return $this->getDefinition()->get('singular_slug'); } public function getContentTypeName(): string { if ($this->getDefinition() === null) { throw new \RuntimeException('Content not fully initialized'); } return $this->getDefinition()->get('singular_name') ?: $this->getContentTypeSlug(); } public function getIcon(): ?string { if ($this->getDefinition() === null) { throw new \RuntimeException('Content not fully initialized'); } return $this->getDefinition()->get('icon_one') ?: $this->getDefinition()->get('icon_many'); } public function getAuthor(): User { return $this->author; } public function setAuthor(?User $author): void { $this->author = $author; } public function getStatus(): string { if (Statuses::isValid($this->status) === false) { $this->status = $this->getDefinition()->get('default_status'); } return $this->status; } public function setStatus(string $status): self { if (Statuses::isValid($status)) { $this->status = $status; } return $this; } public function getCreatedAt(): \DateTime { return $this->createdAt; } public function setCreatedAt(\DateTime $createdAt): self { $this->createdAt = $createdAt; return $this; } public function getModifiedAt(): ?\DateTime { return $this->modifiedAt; } public function setModifiedAt(?\DateTime $modifiedAt): self { $this->modifiedAt = $modifiedAt; return $this; } public function getPublishedAt(): ?\DateTime { return $this->publishedAt; } public function setPublishedAt(?\DateTime $publishedAt): self { $this->publishedAt = $publishedAt; return $this; } public function getDepublishedAt(): ?\DateTime { return $this->depublishedAt; } public function setDepublishedAt(?\DateTime $depublishedAt): self { $this->depublishedAt = $depublishedAt; return $this; } /** * @return Collection|Field[] */ public function getFields(): Collection { return $this->fields; } /** * @Groups("get_content") */ public function getFieldValues(): array { $fieldValues = []; foreach ($this->getFields() as $field) { $fieldValues[$field->getName()] = $field->getFlattenedValue(); } return $fieldValues; } /** * @Groups("get_content") */ public function getTaxonomyValues(): array { $taxonomyValues = []; foreach ($this->getTaxonomies() as $taxonomy) { if (isset($taxonomyValues[$taxonomy->getType()]) === false) { $taxonomyValues[$taxonomy->getType()] = []; } $taxonomyValues[$taxonomy->getType()][$taxonomy->getSlug()] = $taxonomy->getName(); } return $taxonomyValues; } /** * @return array|mixed|null */ public function getFieldValue(string $fieldName) { if ($this->hasField($fieldName) === false) { return null; } return $this->getField($fieldName)->getFlattenedValue(); } public function getField(string $fieldName): Field { if ($this->hasField($fieldName) === false) { throw new \InvalidArgumentException(sprintf("Content does not have '%s' field", $fieldName)); } return $this->fields[$fieldName]; } public function hasField(string $fieldName): bool { return isset($this->fields[$fieldName]); } public function hasFieldDefined(string $fieldName): bool { return $this->contentTypeDefinition->get('fields')->has($fieldName); } public function addField(Field $field): self { if ($this->hasField($field->getName())) { throw new \InvalidArgumentException(sprintf("Content already has '%s' field", $field->getName())); } $this->fields[$field->getName()] = $field; $field->setContent($this); return $this; } public function removeField(Field $field): self { unset($this->fields[$field->getName()]); // set the owning side to null (unless already changed) if ($field->getContent() === $this) { $field->setContent(null); } return $this; } /** * @Groups("get_content") */ public function getAuthorName(): string { return $this->getAuthor()->getDisplayName(); } public function getStatuses(): array { return Statuses::all(); } public function getStatusOptions(): array { $options = []; foreach (Statuses::all() as $option) { $options[] = [ 'key' => $option, 'value' => ucwords($option), 'selected' => $option === $this->getStatus(), ]; } return $options; } /** * @return Collection|Taxonomy[] */ public function getTaxonomies(?string $type = null): Collection { if ($type) { return $this->taxonomies->filter( function (Taxonomy $taxonomy) use ($type) { return $taxonomy->getType() === $type; } ); } return $this->taxonomies; } public function addTaxonomy(Taxonomy $taxonomy): self { if ($this->taxonomies->contains($taxonomy) === false) { $this->taxonomies[] = $taxonomy; $taxonomy->addContent($this); } return $this; } public function removeTaxonomy(Taxonomy $taxonomy): self { if ($this->taxonomies->contains($taxonomy)) { $this->taxonomies->removeElement($taxonomy); $taxonomy->removeContent($this); } return $this; } /** * Generic getter for a record fields. Will return the field with $name. * * If $name is not found, throw an exception if it's invoked from code, and * return null if invoked from within a template. In templates we need to be * more lenient, in order to do things like `{% if record.foo %}..{% endif %} * * Note: We can not rely on `{% if record.foo is defined %}`, because it * always returns `true` for object properties. * See: https://craftcms.stackexchange.com/questions/2116/twig-is-defined-always-returning-true * * - {{ record.title }} => field named title * - {{ record|title }} => value of guessed title field * - {{ record.image }} => field named image * - {{ record|image }} => value of guessed image field */ public function __call(string $name, array $arguments = []) { try { $field = $this->getField($name); } catch (\InvalidArgumentException $e) { $backtrace = new LaravelCollection($e->getTrace()); if ($backtrace->contains('class', \Twig\Template::class)) { // Invoked from within a Template render, so be lenient. return null; } // Invoked from code, throw Exception throw new \RuntimeException(sprintf('Invalid field name or method call on %s: %s', $this->__toString(), $name)); } return $field->getTwigValue(); } }