<?php
|
namespace JVBase\base;
|
use JVBase\meta\Meta;
|
use JVBase\registrar\config\seo\Resolver;
|
use JVBase\registrar\Registrar;
|
|
class SchemaHelper
|
{
|
protected static array $allowedTypes;
|
protected static array $allowedFormats = ['schema', 'archive', 'meta', 'reference'];
|
protected static array $schemas = [];
|
protected static array $metas = [];
|
protected static array $archives = [];
|
protected static array $references = [];
|
public function __construct()
|
{
|
self::$allowedTypes = array_merge(['website', 'organization'], Registrar::getRegistered());
|
}
|
public static function checkType(string $type, string $reference = '[SchemaHelper] Invalid type'):string|false
|
{
|
$type = strtolower($type);
|
if (!in_array($type, self::$allowedTypes)) {
|
error_log($reference.': '.$type);
|
return false;
|
}
|
return $type;
|
}
|
public static function checkFormat(string $format, string $reference = '[SchemaHelper] Invalid format'):string|false
|
{
|
$format = strtolower($format);
|
if (!in_array($format, self::$allowedFormats)) {
|
error_log($reference.': '.$format);
|
return false;
|
}
|
return $format;
|
}
|
public static function getConfig(string $type, string $format):array
|
{
|
$reference = '[SchemaHelper]::getConfig';
|
$type = self::checkType($type, $reference);
|
$format = self::checkFormat($format, $reference);
|
if (!$type || !$format) {
|
return [];
|
}
|
return match($format) {
|
'schema' => self::schema($type),
|
'archive' => self::archive($type),
|
'meta' => self::meta($type),
|
'reference' => self::reference($type),
|
};
|
}
|
public static function schema(string $type): array
|
{
|
$type = self::checkType($type, '[SchemaHelper]::schema');
|
if (!$type) {
|
return [];
|
}
|
|
if (!array_key_exists($type, self::$schemas)) {
|
self::$schemas[$type] = get_option(BASE.ucfirst($type).'Schema', self::getDefault($type, 'schema'));
|
}
|
return self::$schemas[$type];
|
}
|
public static function meta(string $type): array
|
{
|
$type = self::checkType($type, '[SchemaHelper]::meta');
|
if (!$type) {
|
return [];
|
}
|
if (!array_key_exists($type, self::$metas)) {
|
self::$metas[$type] = get_option(BASE.ucfirst($type).'Meta', self::getDefault($type, 'meta'));
|
}
|
return self::$metas[$type];
|
}
|
public static function archive(string $type): array
|
{
|
$type = self::checkType($type, '[SchemaHelper]::archive');
|
|
if (!$type) {
|
return [];
|
}
|
|
if (!array_key_exists($type, self::$archives)) {
|
self::$archives[$type] = get_option(BASE.ucfirst($type).'Archive', self::getDefault($type, 'archive'));
|
}
|
return self::$archives[$type];
|
}
|
public static function reference(string $type): array
|
{
|
$type = self::checkType($type, '[SchemaHelper]::reference');
|
if (!$type) {
|
return [];
|
}
|
if (!array_key_exists($type, self::$references)) {
|
self::$references[$type] = get_option(BASE.ucfirst($type).'Reference', self::getDefault($type, 'reference'));
|
}
|
return self::$references[$type];
|
}
|
|
public static function getDefault(string $type, string $format):array
|
{
|
$reference = '[SchemaHelper]::getDefault';
|
$type = self::checkType($type, $reference);
|
$format = self::checkFormat($format, $reference);
|
if (!$type || !$format) {
|
return [];
|
}
|
|
$defaults = match ($format) {
|
'schema' => match ($type) {
|
'website' => [
|
'type' => 'JVBase\managers\SEO\render\Thing\CreativeWork\WebSite',
|
'name' => get_bloginfo('name'),
|
'url' => get_home_url(),
|
'id' => get_home_url() . '/#website',
|
'description' => get_bloginfo('description'),
|
'inLanguage' => 'en-CA'
|
],
|
default => []
|
},
|
'archive' => [
|
'type' => 'JVBase\inc\managers\SEO\render\Thing\CreativeWork\WebPage\CollectionPage\CollectionPage',
|
'name' => '{{name}}'
|
],
|
default => [],
|
};
|
|
|
$result = apply_filters(BASE.ucfirst($type).ucfirst($format).'Default', $defaults);
|
if ($format === 'reference' && empty($result)) {
|
$full = self::getDefault($type, 'schema');
|
if (!empty($full)) {
|
$result = [
|
'type' => $full['type'],
|
'name' => $full['name'],
|
'description'=> $full['description']
|
];
|
$check = ['id', 'url'];
|
foreach ($check as $ch) {
|
if (array_key_exists($ch, $full)) {
|
$result[$ch] = $full[$ch];
|
}
|
}
|
}
|
}
|
return $result;
|
}
|
|
public static function updateHistory(string $type, string $format, array $newest):bool
|
{
|
$reference = '[SchemaHelper]::updateHistory';
|
$type = self::checkType($type, $reference);
|
$format = self::checkFormat($format, $reference);
|
if (!$type || !$format) {
|
return false;
|
}
|
|
$historyOption = BASE.ucfirst($type).ucfirst($format).'History';
|
$history = get_option($historyOption, []);
|
array_unshift($history, $newest);
|
if (count($history) > 5) {
|
array_pop($history);
|
}
|
return update_option($historyOption, $history);
|
}
|
|
public static function update(string $type, string $format, array $config, ?Meta $meta = null):bool
|
{
|
$reference = '[SchemaHelper]::update';
|
$type = self::checkType($type, $reference);
|
$format = self::checkFormat($format, $reference);
|
if (!$type || !$format) {
|
return false;
|
}
|
$method = 'update'.ucfirst($type);
|
return self::$method($config, $meta);
|
}
|
public static function updateSchema(string $type, array $config):bool
|
{
|
$reference = '[SchemaHelper]::updateSchema';
|
$type = self::checkType($type, $reference);
|
if (!$type) {
|
return false;
|
}
|
if (!class_exists($config['type'])){
|
error_log('[SchemaHelper]::updateSchema Config must be a valid schema type: '.$config['type']);
|
return false;
|
}
|
if (!in_array($type, self::$allowedTypes)) {
|
error_log('[SchemaHelper]::updateSchema Config must have a schema type');
|
}
|
|
return self::updateClassConfig($type, 'schema', $config);
|
}
|
|
public static function updateClassConfig(string $type, string $format, array $config):bool
|
{
|
$reference = '[SchemaHelper]::updateClassConfig';
|
$type = self::checkType($type, $reference);
|
if (!$type) {
|
return false;
|
}
|
if (!class_exists($config['type'])){
|
error_log($reference.' Config must be a valid schema type: '.$config['type']);
|
return false;
|
}
|
if (!in_array($type, self::$allowedTypes)) {
|
error_log($reference.' Config must have a schema type');
|
}
|
//Merge stored config with updates
|
$stored = self::schema($type);
|
$update = array_merge_recursive($stored, $config);
|
|
//Validate Properties
|
$className = $update['type'];
|
unset($update['type']);
|
foreach ($update as $property => $value) {
|
if (!property_exists($className, $property)) {
|
error_log($reference.' invalid property attempted: '.$property.', with value: '.print_r($value, true).' for class: '.$className);
|
unset($update[$property]);
|
}
|
}
|
$update['type'] = $className;
|
|
//Add changes to history (keeps last 5 changes)
|
self::updateHistory($type, $format, $update);
|
self::$schemas[$type] = $update;
|
return update_option(BASE.ucfirst($type).ucfirst($format), $update);
|
}
|
|
public static function updateMeta(string $type, array $config):bool
|
{
|
$type = self::checkType($type, '[SchemaHelper]::updateMeta');
|
$allowed = array_filter($config, function($key) {
|
$allowed = in_array($key, ['name', 'description']);
|
if (!$allowed) {
|
error_log('[SchemaHelper]::updateMeta invalid property attempted: '.$key);
|
}
|
return $allowed;
|
});
|
if (empty($allowed)) {
|
error_log('[SchemaHelper]::updateMeta Name or Description must be set');
|
return false;
|
}
|
$config = array_map('sanitize_text_field', $config);
|
self::updateHistory($type, 'meta', $config);
|
self::$metas[$type] = $config;
|
return update_option(BASE.ucfirst($type).'Meta', $config);
|
}
|
|
public static function updateArchive(string $type, array $config):bool
|
{
|
$reference = '[SchemaHelper]::updateArchive';
|
$type = self::checkType($type, $reference);
|
if (!$type) {
|
return false;
|
}
|
if (!class_exists($config['type'])){
|
error_log('[SchemaHelper]::updateSchema Config must be a valid schema type: '.$config['type']);
|
return false;
|
}
|
if (!in_array($type, self::$allowedTypes)) {
|
error_log('[SchemaHelper]::updateSchema Config must have a schema type');
|
}
|
|
return self::updateClassConfig($type, 'schema', $config);
|
}
|
|
public static function classFromConfig(array $config, ?Meta $meta = null):mixed
|
{
|
if (!array_key_exists('type', $config)) {
|
error_log('[SchemaHelper]::classFromConfig No class defined in config: '.print_r($config, true));
|
return false;
|
}
|
$className = $config['type'];
|
unset($config['type']);
|
$class = new $className();
|
if (array_key_exists('id', $config)) {
|
$class->setId($config['id']);
|
unset($config['id']);
|
}
|
|
|
foreach ($config as $property => $value) {
|
if (is_array($value) && array_key_exists('type', $value)) {
|
$value = self::classFromConfig($value, $meta);
|
}
|
$method = 'set'.ucfirst($property);
|
if (!method_exists($class, $method)) {
|
error_log('[SchemaHelper]::classFromConfig - method: '.$method.' does not exist in class: '.$className);
|
continue;
|
}
|
if (is_string($value) && str_contains($value, '{{')) {
|
$value = Resolver::resolveForSchema($property, $value, $config, $meta);
|
}
|
if (!empty($value)) {
|
$class->$method($value);
|
}
|
}
|
return $class;
|
}
|
}
|