Skip to content

Commit

Permalink
Merge pull request #90 from thefrosty/develop
Browse files Browse the repository at this point in the history
v2.7.0
  • Loading branch information
thefrosty authored Mar 28, 2022
2 parents 8daf7e6 + bb0e4c4 commit ef5dc60
Show file tree
Hide file tree
Showing 9 changed files with 606 additions and 115 deletions.
126 changes: 126 additions & 0 deletions src/Api/WpRemote.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
<?php declare(strict_types=1);

namespace TheFrosty\WpUtilities\Api;

use TheFrosty\WpUtilities\Plugin\Plugin;
use function apply_filters;
use function array_filter;
use function array_merge;
use function esc_attr;
use function esc_url;
use function get_bloginfo;
use function is_wp_error;
use function sprintf;
use function strtolower;
use function ucfirst;
use function wp_remote_get;
use function wp_remote_post;
use const DAY_IN_SECONDS;

/**
* Trait WpRemote
* @package TheFrosty\WpUtilities\Api
*/
trait WpRemote
{

use WpCacheTrait;

/**
* Get the remote GET request body.
* @param string $url The URL to make a remote request too.
* @param array $args Additional request args.
* @param string $method The method type (supports GET & POST only).
* @return mixed
*/
public function retrieveBody(string $url, array $args = [], string $method = 'GET')
{
if (!in_array($method, ['GET', 'POST'], true)) {
return false;
}
$function = sprintf('wpRemote%1$s', ucfirst(strtolower($method)));
$response = wp_remote_retrieve_body($this->$function(esc_url($url), $this->buildRequestArgs($args)));
if (!is_wp_error($response) && $response !== '') {
$body = json_decode($response);
if ($body === null) {
return false;
}
}

return $body ?? false;
}

/**
* Get the remote GET request body cached.
* @param string $url
* @param int|null $expiration
* @param string|null $user_agent
* @param string|null $version
* @return false|mixed
*/
public function retrieveBodyCached(
string $url,
?int $expiration = 0,
?string $user_agent = null,
?string $version = null
) {
$key = $this->getHashedKey($url);
$body = $this->getCache($key);
if (empty($body)) {
if ($user_agent !== null) {
$args = [
'user-agent' => esc_attr(sprintf(
'%s/%s; %s',
$user_agent,
$version ?? $GLOBALS['wp_version'],
get_bloginfo('url')
)),
];
}
$body = $this->retrieveBody($url, $args ?? []);
if (!empty($body)) {
$this->setCache($key, $body, null, $expiration ?? DAY_IN_SECONDS);
}

return $body;
}

return $body;
}

/**
* Return a remote GET request.
* @param string $url
* @param array $args
* @return array|\WP_Error
*/
public function wpRemoteGet(string $url, array $args = [])
{
return wp_remote_get(esc_url($url), $this->buildRequestArgs($args));
}

/**
* Return a remote POST request.
* @param string $url
* @param array $args
* @return array|\WP_Error
*/
public function wpRemotePost(string $url, array $args = [])
{
return wp_remote_post(esc_url($url), $this->buildRequestArgs($args));
}

/**
* Build Request args.
* @param array $args
* @return array
*/
private function buildRequestArgs(array $args): array
{
$defaults = [
'timeout' => apply_filters(Plugin::TAG . 'wp_remote_timeout', 15),
];

return array_filter(array_merge($defaults, $args));
}
}
211 changes: 211 additions & 0 deletions src/Utils/View.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,211 @@
<?php declare(strict_types=1);

namespace TheFrosty\WpUtilities\Utils;

use RuntimeException;
use function array_merge;
use function array_unshift;
use function count;
use function current_filter;
use function dirname;
use function extract;
use function file_exists;
use function function_exists;
use function get_object_vars;
use function is_array;
use function is_object;
use function ob_get_clean;
use function ob_start;
use function realpath;
use function sprintf;
use function str_replace;
use function trailingslashit;

/**
* Class View
* @package TheFrosty\WpUtilities\Utils
*/
final class View
{

/**
* List of paths to load views from.
* Internal loader selects the first path with file that exists.
* Paths that are loaded with addPath are prepended to the array.
* @var array $viewPaths
*/
protected array $viewPaths = [];

/**
* View data
* @var array $viewData
*/
private array $viewData = [];

/**
* View constructor.
*/
public function __construct()
{
$this->setDefaultPaths();
}

/**
* Return a view file.
* @param string $view The view file to render from the `views` directory.
* @return string|null
*/
public function get(string $view): ?string
{
$file = $this->sanitizeFileExtension($view . '.php');

return $this->getViewPath($file);
}

/**
* Render a view.
* @param string $filename The view file to render from the `views` directory.
* @param array $viewData
*/
public function render(string $filename, array $viewData = []): void
{
/*
* Clear view data, so we can use the same object multiple times,
* otherwise the view data will persist and may cause problems.
*/
$this->viewData = [];
$this->load([$filename, $viewData]);
}

/**
* Return a view.
* @param string $filename The view file to render from the `views` directory.
* @param array $viewData
* @return string
*/
public function retrieve(string $filename, array $viewData = []): string
{
ob_start();
$this->render($filename, $viewData);

return ob_get_clean();
}

/**
* Set variables to be available in any view
* @param array|object $vars
*/
public function setVars($vars = []): void
{
if (is_object($vars)) {
$vars = get_object_vars($vars);
}

if (is_array($vars) and count($vars) > 0) {
foreach ($vars as $key => $val) {
$this->viewData[$key] = $val;
}
}
}

/**
* Add View Path. Prepend the paths array with the new path
* @param string $path
*/
public function addPath(string $path): void
{
array_unshift($this->viewPaths, trailingslashit(realpath($path)));
}

/**
* Get view data.
* @return array
*/
public function getViewData(): array
{
return $this->viewData;
}

/**
* Internal view loader
* @param array<string, array> $args
* @throws RuntimeException
*/
private function load(array $args): void
{
$this->setDefaultPaths();
[$view, $data] = $args;

// Add a file extension the view
$file = $this->sanitizeFileExtension($view . '.php');

// Get the view path
$viewPath = $this->getViewPath($file);

// Display error if view not found
if ($viewPath === null) {
$this->viewNotFoundError($file);
}

if (is_array($data) && !empty($data)) {
$this->viewData = array_merge($this->viewData, $data);
}

extract($this->viewData);
include $viewPath;
}

/**
* Set the default paths.
* The default view directories always need to be loaded first
*/
private function setDefaultPaths(): void
{
if (empty($this->viewPaths)) {
$this->viewPaths = [sprintf('%1$s/views/', dirname(__DIR__, 2))];
}
}

/**
* Sanitize the file extension.
* @param string $file
* @return string
*/
private function sanitizeFileExtension(string $file): string
{
return str_replace('.php.php', '.php', $file);
}

/**
* Get the view path.
* @param string $file
* @return string|null
*/
private function getViewPath(string $file): ?string
{
$file = $this->sanitizeFileExtension($file);
foreach ($this->viewPaths as $viewDir) {
if (file_exists($viewDir . $file)) {
return $viewDir . $file;
}
}

return null;
}

/**
* Display error when no view found.
* @param string $file
* @return mixed
* @throws RuntimeException
*/
private function viewNotFoundError(string $file): void
{
$errText = PHP_EOL .
'View file "' . $file . '" not found.' . PHP_EOL .
'Directories checked: ' . PHP_EOL .
'[' . implode('],' . PHP_EOL . '[', $this->viewPaths) . ']' . PHP_EOL;

throw new RuntimeException($errText);
}
}
48 changes: 48 additions & 0 deletions src/Utils/Viewable.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php declare(strict_types=1);

namespace TheFrosty\WpUtilities\Utils;

use Psr\Container\ContainerInterface;
use RuntimeException;
use TheFrosty\WpUtilities\Plugin\ContainerAwareTrait;
use Throwable;
use function get_class;
use function method_exists;

/**
* Trait Viewable
* @package TheFrosty\WpUtilities\Utils
*/
trait Viewable
{

/**
* View instance.
* @var View|null
*/
private ?View $view = null;

/**
* Get an instance of View.
* @param string $id Identifier of the entry to look for.
* @return View|null View object, null if
*/
public function getView(string $id): ?View
{
if (!method_exists($this, 'getContainer') || !$this->getContainer() instanceof ContainerInterface) {
throw new RuntimeException(
sprintf('%s must use %s', get_class($this), ContainerAwareTrait::class)
);
}

if (!$this->view instanceof View) {
try {
$this->view = $this->getContainer()->get($id);
} catch (Throwable $e) {
return null;
}
}

return $this->view;
}
}
Loading

0 comments on commit ef5dc60

Please sign in to comment.