Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions app/Config/Options.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

namespace PluginFrame\Config;

use PluginFrame\Core\Services\Container;
use PluginFrame\Core\Services\Options\Interfaces\OptionStorageInterface;
use PluginFrame\Core\Services\Options\WPOptionStorage;
use PluginFrame\Core\Services\Options\CustomTableOption;
use PluginFrame\Core\Services\Options\OptionManager;

class Options
{
public function __construct()
{
$this->pf_options_container_loader();
}

private function pf_options_container_loader(): void
{
Container::bind(
OptionStorageInterface::class . ':wp',
fn($c) => new WPOptionStorage()
);
Container::bind(
OptionStorageInterface::class . ':custom',
fn($c) => new CustomTableOption()
);
Container::bind(
OptionManager::class,
fn($c) => new OptionManager($c)
);
Container::bind(
OptionStorageInterface::class,
fn($c) => $c->get(OptionStorageInterface::class . ':wp')
);
}
}
Empty file removed app/Config/index.php
Empty file.
Empty file removed app/Core/API/index.php
Empty file.
Empty file removed app/Core/DB/Migrations/index.php
Empty file.
Empty file removed app/Core/DB/Models/index.php
Empty file.
Empty file removed app/Core/DB/Pagination/index.php
Empty file.
Empty file removed app/Core/DB/Seeders/index.php
Empty file.
Empty file removed app/Core/DB/Utils/index.php
Empty file.
Empty file removed app/Core/DB/WP/index.php
Empty file.
Empty file removed app/Core/DB/index.php
Empty file.
3 changes: 3 additions & 0 deletions app/Core/Helpers/BootstrapHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,9 @@ private function load_features(): void
{
(new \PluginFrame\Config\Config())->priority_load_first();

// Initialize Options Container and Storage Services
new \PluginFrame\Config\Options();

// Initialize providers and configuration.
new \PluginFrame\Config\Providers();

Expand Down
22 changes: 22 additions & 0 deletions app/Core/Helpers/OptionsHelper.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php
namespace PluginFrame\Core\Helpers;

use PluginFrame\Core\Services\Container;
use PluginFrame\Core\Services\Options\OptionManager;

if (! defined('ABSPATH')) {
exit;
}

if (! function_exists('pf_options')) {
/**
* Shortcut to retrieve the global OptionManager.
*
* @return OptionManager
*/
function pf_options(): OptionManager
{
// Use the static resolve() alias to fetch the manager
return Container::resolve(OptionManager::class);
}
}
Empty file removed app/Core/Helpers/index.php
Empty file.
Empty file removed app/Core/Hooks/index.php
Empty file.
2 changes: 0 additions & 2 deletions app/Core/PluginFrame.php
Original file line number Diff line number Diff line change
@@ -1,2 +0,0 @@
<?php

Empty file.
Empty file removed app/Core/Routes/index.php
Empty file.
90 changes: 90 additions & 0 deletions app/Core/Services/Container.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
namespace PluginFrame\Core\Services;

use Psr\Container\ContainerInterface;
use Psr\Container\NotFoundExceptionInterface;

/**
* A simple PSR-11–compatible service container.
* Implements a static singleton for global access.
*/
class Container implements ContainerInterface
{
/** @var Container|null */
private static ?Container $instance = null;

/** @var array<string, callable> */
private array $definitions = [];

/** @var array<string, mixed> */
private array $instances = [];

/** Private to enforce singleton */
private function __construct() {}

/**
* Retrieve the singleton instance.
*/
public static function getInstance(): Container
{
return self::$instance ??= new Container();
}

/**
* Bind a service ID to a resolver callable.
*
* @param string $id Service identifier.
* @param callable $resolver function(ContainerInterface): mixed
*/
public static function bind(string $id, callable $resolver): void
{
self::getInstance()->definitions[$id] = $resolver;
}

/**
* Resolve a service by its ID.
*
* @param string $id Identifier of the entry to look for.
* @return mixed The entry.
* @throws NotFoundExceptionInterface No entry was found for this identifier.
*/
public function get(string $id): mixed
{
if (isset($this->instances[$id])) {
return $this->instances[$id];
}

if (! isset($this->definitions[$id])) {
throw new class("Service {$id} not found")
extends \Exception
implements NotFoundExceptionInterface {};
}

$resolver = $this->definitions[$id];
$service = $resolver($this);
$this->instances[$id] = $service;
return $service;
}

/**
* Static shortcut to resolve a service.
*
* @param string $id
* @return mixed
*/
public static function resolve(string $id): mixed
{
return self::getInstance()->get($id);
}

/**
* Does this container have a resolver bound for $id?
*
* @param string $id Identifier to check.
* @return bool
*/
public function has(string $id): bool
{
return isset($this->definitions[$id]);
}
}
57 changes: 57 additions & 0 deletions app/Core/Services/Options/CompositeOptionStorage.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php
namespace PluginFrame\Core\Services\Options;

use PluginFrame\Core\Services\Options\Interfaces\OptionStorageInterface;

/**
* Composite driver: writes to multiple storage backends simultaneously.
*/
class CompositeOptionStorage implements OptionStorageInterface
{
/** @var OptionStorageInterface[] */
private array $storages;

public function __construct(array $storages) {
$this->storages = $storages;
}

public function register(string $key, $default = null, array $args = []): void {
foreach ($this->storages as $storage) {
$storage->register($key, $default, $args);
}
}

public function get(string $key, $default = null) {
foreach ($this->storages as $storage) {
$value = $storage->get($key, null);
if (null !== $value) {
return $value;
}
}
return $default;
}

public function update(string $key, $value): bool {
$ok = true;
foreach ($this->storages as $storage) {
$ok = $ok && $storage->update($key, $value);
}
return $ok;
}

public function delete(string $key): bool {
$ok = true;
foreach ($this->storages as $storage) {
$ok = $ok && $storage->delete($key);
}
return $ok;
}

public function all(): array {
$all = [];
foreach ($this->storages as $storage) {
$all = array_merge($all, $storage->all());
}
return $all;
}
}
66 changes: 66 additions & 0 deletions app/Core/Services/Options/CustomTableOption.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php
namespace PluginFrame\Core\Services\Options;

use PluginFrame\Core\Services\Options\Interfaces\OptionStorageInterface;
use wpdb;

/**
* Stores options in a custom DB table for high-volume or structured data.
*/
class CustomTableOption implements OptionStorageInterface
{
private wpdb $db;
private string $table;

public function __construct()
{
global $wpdb;
$this->db = $wpdb;
$this->table = $wpdb->prefix . 'plugin_options';
}

public function register(string $key, $default = null, array $args = []): void
{
$exists = $this->db->get_var(
$this->db->prepare("SELECT COUNT(*) FROM {$this->table} WHERE option_key=%s", $key)
);
if (!$exists) {
$this->db->insert(
$this->table,
['option_key' => $key, 'option_value' => maybe_serialize($default)],
['%s','%s']
);
}
}

public function get(string $key, $default = null)
{
$row = $this->db->get_row(
$this->db->prepare("SELECT option_value FROM {$this->table} WHERE option_key=%s", $key),
ARRAY_A
);
return $row ? maybe_unserialize($row['option_value']) : $default;
}

public function update(string $key, $value): bool
{
return (bool) $this->db->update(
$this->table,
['option_value' => maybe_serialize($value)],
['option_key' => $key],
['%s'],
['%s']
);
}

public function delete(string $key): bool
{
return (bool) $this->db->delete($this->table, ['option_key' => $key], ['%s']);
}

public function all(): array
{
$rows = $this->db->get_results("SELECT * FROM {$this->table}", ARRAY_A);
return array_column($rows, 'option_value', 'option_key');
}
}
49 changes: 49 additions & 0 deletions app/Core/Services/Options/Interfaces/OptionInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
<?php

namespace PluginFrame\Core\Services\Options\Interfaces;

interface OptionInterface
{
/**
* Register a new option into WordPress options table.
*
* @param string $key
* @param mixed $default
* @param array $args Optional args like description, type, group, etc.
* @return void
*/
public function register(string $key, $default = null, array $args = []): void;

/**
* Get all registered options by this service.
*
* @return array
*/
public function all(): array;

/**
* Get a specific option value.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get(string $key, $default = null);

/**
* Update a specific option value.
*
* @param string $key
* @param mixed $value
* @return bool
*/
public function update(string $key, $value): bool;

/**
* Delete a registered option.
*
* @param string $key
* @return bool
*/
public function delete(string $key): bool;
}
14 changes: 14 additions & 0 deletions app/Core/Services/Options/Interfaces/OptionStorageInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php
namespace PluginFrame\Core\Services\Options\Interfaces;

/**
* Defines a storage strategy for plugin frame options.
*/
interface OptionStorageInterface
{
public function register(string $key, $default = null, array $args = []): void;
public function get(string $key, $default = null);
public function update(string $key, $value): bool;
public function delete(string $key): bool;
public function all(): array;
}
16 changes: 0 additions & 16 deletions app/Core/Services/Options/Option.php

This file was deleted.

Loading