wp/src/Posts/Taxonomy/Term.php

177 lines
4.8 KiB
PHP

<?php
namespace vlw\WP\Posts\Taxonomy;
use Exception;
use vlw\Scaffold\Database\Model;
use vlw\WP\Database;
use vlw\WP\Posts\Post;
use vlw\WP\Tables\Terms;
use vlw\WP\Posts\Taxonomy\Taxonomy;
use vlw\WP\Tables\TermRelationships;
use function vlw\WP\Support\slugify;
require_once dirname(__DIR__, 1) . "/Post.php";
require_once dirname(__DIR__, 2) . "/Tables/Terms.php";
require_once dirname(__DIR__, 2) . "/Support/Slugify.php";
require_once dirname(__DIR__, 2) . "/Tables/TermRelationships.php";
class Term extends Model {
/**
* Returns a Term by a name
*
* @param string $name
* @return static|null
*/
public static function from_name(string $name): ?static {
$query = Database::current()
->from(Database::get_table(Terms::TABLE_NAME))
->where([Terms::NAME->value => $name])
->limit(1)
->select(Terms::TERM_ID->value);
return $query->num_rows === 1 ? new static($query->fetch_assoc()[Terms::TERM_ID->value]) : null;
}
/**
* Returns an array of all Terms associated with a Post
*
* @param Post $post
* @return array
*/
public static function from_post(Post $post): array {
$query = Database::current()
->from(Database::get_table(TermRelationships::TABLE_NAME))
->where([TermRelationships::OBJECT_ID->value => $post->id])
->select(TermRelationships::TERM_TAXONOMY_ID->value);
return array_map(fn(array $post_meta): static => new static($post_meta[TermRelationships::TERM_TAXONOMY_ID->value]), $query->fetch_all(MYSQLI_ASSOC));
}
/**
* Create a new post meta field for a given post
*
* @param string $title Post title
* @param string $type Post type
* @return static
*/
public static function new(string $name, ?string $slug = null): static {
// Current auto increment value will be the id for this entity
$id = Database::current()->latest(Terms::TABLE_NAME);
$values = [
Terms::TERM_ID->value => null,
Terms::NAME->value => $name,
Terms::SLUG->value => $slug ? $slug : slugify($name),
Terms::TERM_GROUP->value => 0
];
if (!parent::create(Database::get_table(Terms::TABLE_NAME), $values)) {
throw new Exception("Failed to create database entity");
}
return new static($id);
}
public function __construct(public readonly int $id) {
parent::__construct(
Database::get_table(Terms::TABLE_NAME),
Terms::values(),
[Terms::TERM_ID->value => $id]
);
}
public string $name {
get => $this->get(Terms::NAME->value);
set (string $name) => $this->set(Terms::NAME->value, $name);
}
public string $slug {
get => $this->get(Terms::SLUG->value);
set (string $slug) => $this->set(Terms::SLUG->value, $slug);
}
public int $term_group {
get => $this->get(Terms::TERM_GROUP->value);
set (int $term_group) => $this->set(Terms::TERM_GROUP->value, $term_group);
}
/**
* Returns an array of Taxonomies that implement this Term
*
* @return array
*/
public function taxonomies(): array {
return Taxonomy::from_term($this);
}
/**
* Add this Term to a target Post
*
* @param Post $post
* @return void
*/
public function add_to_post(Post $post): void {
// Bail out if this term has already been added to the target Post
if ($this->post_has_term($post)) {
return;
}
$query = Database::current()
->from(Database::get_table(TermRelationships::TABLE_NAME))
->insert([
TermRelationships::OBJECT_ID->value => $post->id,
TermRelationships::TERM_TAXONOMY_ID->value => $this->id,
TermRelationships::TERM_ORDER->value => 0
]);
if ($query === false) {
throw new Exception("Failed to create database entity");
}
// Increase the post count for each Taxonomy implementing this Term
foreach ($this->taxonomies() as $taxonomy) {
$taxonomy->count++;
}
}
/**
* Remove this Term from a target Post
*
* @param Post $post
* @return void
*/
public function remove_from_post(Post $post): void {
// Bail out if this Term is not set on the target Post
if (!$this->post_has_term($post)) {
return;
}
$query = Database::current()
->from(Database::get_table(TermRelationships::TABLE_NAME))
->delete([
TermRelationships::OBJECT_ID->value => $post->id,
TermRelationships::TERM_TAXONOMY_ID->value => $this->id
]);
if ($query === false) {
throw new Exception("Failed to create database entity");
}
// Decrease the post count for each Taxonomy implementing this Term
foreach ($this->taxonomies() as $taxonomy) {
$taxonomy->count--;
}
}
/**
* Returns true if a given Post has this Term
*
* @param Post $post
* @return bool
*/
private function post_has_term(Post $post): bool {
return in_array($this->id, array_column(self::from_post($post), "id"));
}
}