Release of v5.1.1-beta1
Add JCB new package engine.
This commit is contained in:
367
libraries/vendor_jcb/VDM.Joomla.Git/src/Repository/Contents.php
Normal file
367
libraries/vendor_jcb/VDM.Joomla.Git/src/Repository/Contents.php
Normal file
@@ -0,0 +1,367 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Git\Repository;
|
||||
|
||||
|
||||
use VDM\Joomla\Gitea\Repository\Contents as Gitea;
|
||||
use VDM\Joomla\Github\Repository\Contents as Github;
|
||||
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface;
|
||||
|
||||
|
||||
/**
|
||||
* The Git Repository Contents
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Contents implements ContentsInterface
|
||||
{
|
||||
/**
|
||||
* The target system
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $target;
|
||||
|
||||
/**
|
||||
* The Contents Class.
|
||||
*
|
||||
* @var Gitea
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Gitea $gitea;
|
||||
|
||||
/**
|
||||
* The Contents Class.
|
||||
*
|
||||
* @var Github
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Github $github;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Gitea $gitea The Contents Class.
|
||||
* @param Github $github The Contents Class.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(Gitea $gitea, Github $github)
|
||||
{
|
||||
$this->gitea = $gitea;
|
||||
$this->github = $github;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the target system to use (gitea or github)
|
||||
*
|
||||
* @param string $system
|
||||
*
|
||||
* @return void
|
||||
* @throws \DomainException
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function setTarget(string $system): void
|
||||
{
|
||||
$system = strtolower(trim($system));
|
||||
|
||||
if (!in_array($system, ['gitea', 'github'], true))
|
||||
{
|
||||
throw new \DomainException("Invalid target system: {$system}");
|
||||
}
|
||||
|
||||
$this->target = $system;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure a valid target is set
|
||||
*
|
||||
* @return string
|
||||
* @throws \DomainException
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getTarget(): string
|
||||
{
|
||||
if ($this->target === null)
|
||||
{
|
||||
throw new \DomainException('No target system selected. Use $this->target("gitea"|"github") before calling this method.');
|
||||
}
|
||||
return $this->target;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load/Reload API.
|
||||
*
|
||||
* @param string|null $url The url.
|
||||
* @param string|null $token The token.
|
||||
* @param bool $backup The backup swapping switch.
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function load_(?string $url = null, ?string $token = null, bool $backup = true): void
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
$this->{$target}->load_($url, $token, $backup);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to previous toke, url it set
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function reset_(): void
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
$this->{$target}->reset_();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API url
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function api()
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
$this->{$target}->api();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a file from a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string|null $ref Optional. The name of the commit/branch/tag.
|
||||
* Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return mixed
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function get(string $owner, string $repo, string $filepath, ?string $ref = null)
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->get($owner, $repo, $filepath, $ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata and contents (if a file) of an entry in a repository,
|
||||
* or a list of entries if a directory.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file or directory path.
|
||||
* @param string|null $ref Optional. The name of the commit/branch/tag.
|
||||
* Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return null|array|object
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function metadata(string $owner, string $repo, string $filepath, ?string $ref = null): null|array|object
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->metadata($owner, $repo, $filepath, $ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $content The file content.
|
||||
* @param string $message The commit message.
|
||||
* @param string $branch The branch name. Defaults to the repository's default branch.
|
||||
* @param string|null $authorName The author's name.
|
||||
* @param string|null $authorEmail The author's email.
|
||||
* @param string|null $committerName The committer's name.
|
||||
* @param string|null $committerEmail The committer's email.
|
||||
* @param string|null $newBranch Whether to create a new branch. Defaults to null.
|
||||
* @param string|null $authorDate The author's date.
|
||||
* @param string|null $committerDate The committer's date.
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer. Defaults to null.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function create(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $content,
|
||||
string $message,
|
||||
string $branch = 'master',
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $newBranch = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->create(
|
||||
$owner, $repo, $filepath, $content, $message, $branch,
|
||||
$authorName, $authorEmail, $committerName, $committerEmail,
|
||||
$newBranch, $authorDate, $committerDate, $signoff
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata of all the entries of the root directory.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string|null $ref The name of the commit/branch/tag. Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return array|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function root(string $owner, string $repo, ?string $ref = null): ?array
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->root($owner, $repo, $ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $content The file content.
|
||||
* @param string $message The commit message.
|
||||
* @param string $sha The blob SHA of the file.
|
||||
* @param string $branch The branch name. Defaults to the repository's default branch.
|
||||
* @param string|null $authorName The author name. Defaults to the authenticated user.
|
||||
* @param string|null $authorEmail The author email. Defaults to the authenticated user.
|
||||
* @param string|null $committerName The committer name. Defaults to the authenticated user.
|
||||
* @param string|null $committerEmail The committer email. Defaults to the authenticated user.
|
||||
* @param string|null $authorDate The author date.
|
||||
* @param string|null $committerDate The committer date.
|
||||
* @param string|null $fromPath The original file path to move/rename.
|
||||
* @param string|null $newBranch The new branch to create from the specified branch.
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function update(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $content,
|
||||
string $message,
|
||||
string $sha,
|
||||
string $branch = 'master',
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?string $fromPath = null,
|
||||
?string $newBranch = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->update(
|
||||
$owner, $repo, $filepath, $content, $message, $sha, $branch,
|
||||
$authorName, $authorEmail, $committerName, $committerEmail,
|
||||
$authorDate, $committerDate, $fromPath, $newBranch, $signoff
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $message The commit message.
|
||||
* @param string $sha The blob SHA of the file.
|
||||
* @param string|null $branch The branch name (optional).
|
||||
* @param string|null $authorName The author name (optional).
|
||||
* @param string|null $authorEmail The author email (optional).
|
||||
* @param string|null $committerName The committer name (optional).
|
||||
* @param string|null $committerEmail The committer email (optional).
|
||||
* @param string|null $authorDate The author date (optional).
|
||||
* @param string|null $committerDate The committer date (optional).
|
||||
* @param string|null $newBranch The new branch name (optional).
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer (optional).
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function delete(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $message,
|
||||
string $sha,
|
||||
?string $branch = null,
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?string $newBranch = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->delete(
|
||||
$owner, $repo, $filepath, $message, $sha, $branch,
|
||||
$authorName, $authorEmail, $committerName, $committerEmail,
|
||||
$authorDate, $committerDate, $newBranch, $signoff
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EditorConfig definitions of a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string|null $ref The name of the commit/branch/tag.
|
||||
*
|
||||
* @return string|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function editor(string $owner, string $repo, string $filepath, string $ref = null): ?string
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->editor($owner, $repo, $filepath, $ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blob of a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $sha The SHA hash of the blob.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function blob(string $owner, string $repo, string $sha): ?object
|
||||
{
|
||||
$target = $this->getTarget();
|
||||
return $this->{$target}->blob($owner, $repo, $sha);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -154,7 +154,7 @@ class Issue extends Api
|
||||
return $this->response->get(
|
||||
$this->http->post(
|
||||
$this->uri->get($path), json_encode($data)
|
||||
)
|
||||
), 201
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,6 @@ namespace VDM\Joomla\Gitea\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Http\Http as JoomlaHttp;
|
||||
use Joomla\CMS\Uri\Uri;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Gitea\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Http\Response as JoomlaResponse;
|
||||
use Joomla\Http\Response as JoomlaResponse;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
|
||||
@@ -36,7 +36,7 @@ final class Response
|
||||
* @since 3.2.0
|
||||
* @throws \DomainException
|
||||
**/
|
||||
public function get($response, int $expectedCode = 200, $default = null)
|
||||
public function get(JoomlaResponse $response, int $expectedCode = 200, $default = null)
|
||||
{
|
||||
// Validate the response code.
|
||||
if ($response->code != $expectedCode)
|
||||
@@ -44,8 +44,7 @@ final class Response
|
||||
// Decode the error response and throw an exception.
|
||||
$message = $this->error($response);
|
||||
|
||||
throw new \DomainException("Invalid response received from API. $message", $response->code);
|
||||
|
||||
throw new \DomainException("Invalid response received from Gitea API. $message", $response->code);
|
||||
}
|
||||
|
||||
return $this->body($response, $default);
|
||||
@@ -62,7 +61,7 @@ final class Response
|
||||
* @since 3.2.0
|
||||
* @throws \DomainException
|
||||
**/
|
||||
public function get_($response, array $validate = [200 => null])
|
||||
public function get_(JoomlaResponse $response, array $validate = [200 => null])
|
||||
{
|
||||
// Validate the response code.
|
||||
if (!isset($validate[$response->code]))
|
||||
@@ -70,8 +69,7 @@ final class Response
|
||||
// Decode the error response and throw an exception.
|
||||
$message = $this->error($response);
|
||||
|
||||
throw new \DomainException("Invalid response received from API. $message", $response->code);
|
||||
|
||||
throw new \DomainException("Invalid response received from Gitea API. $message", $response->code);
|
||||
}
|
||||
|
||||
return $this->body($response, $validate[$response->code]);
|
||||
@@ -86,11 +84,14 @@ final class Response
|
||||
* @return mixed
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected function body($response, $default = null)
|
||||
protected function body(JoomlaResponse $response, $default = null)
|
||||
{
|
||||
$body = $response->body ?? null;
|
||||
$body = is_object($response) && method_exists($response, 'getBody')
|
||||
? (string) $response->getBody()
|
||||
: (isset($response->body) ? (string) $response->body : null);
|
||||
|
||||
// check that we have a body
|
||||
if (StringHelper::check($body))
|
||||
if ($body !== null && StringHelper::check($body))
|
||||
{
|
||||
if (JsonHelper::check($body))
|
||||
{
|
||||
@@ -116,41 +117,44 @@ final class Response
|
||||
* @return string The extracted error message, or an empty string.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function error($response): string
|
||||
protected function error(JoomlaResponse $response): string
|
||||
{
|
||||
// JSON decode helpers
|
||||
$decodeJson = static fn($value) => JsonHelper::check($value) ? json_decode($value, true) : null;
|
||||
$decodeJsonObject = static fn($value) => JsonHelper::check($value) ? json_decode($value) : null;
|
||||
// Try to get the raw response body
|
||||
$body = method_exists($response, 'getBody') ? (string) $response->getBody() : '';
|
||||
|
||||
// Try decoding from body
|
||||
if (!empty($response->body))
|
||||
// Try to decode as JSON object
|
||||
$errorData = JsonHelper::check($body) ? json_decode($body) : null;
|
||||
|
||||
if (is_object($errorData))
|
||||
{
|
||||
$errorData = $decodeJsonObject($response->body);
|
||||
|
||||
if (is_object($errorData))
|
||||
// Try to extract a useful error field
|
||||
if (!empty($errorData->error))
|
||||
{
|
||||
return $errorData->error ?? $errorData->message ?? '';
|
||||
return $errorData->error;
|
||||
}
|
||||
|
||||
if (!empty($errorData->message))
|
||||
{
|
||||
return $errorData->message;
|
||||
}
|
||||
|
||||
// Fallback to a serialized message
|
||||
return json_encode($errorData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
// Try decoding from errors
|
||||
if (!empty($response->errors))
|
||||
// Fallback to reason phrase or body
|
||||
if (!empty($body))
|
||||
{
|
||||
$errorArray = $decodeJson($response->errors);
|
||||
|
||||
if (is_array($errorArray))
|
||||
{
|
||||
if (!empty($response->message) && StringHelper::check($response->message))
|
||||
{
|
||||
array_unshift($errorArray, $response->message);
|
||||
}
|
||||
|
||||
return implode("\n", $errorArray);
|
||||
}
|
||||
return $body;
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return '';
|
||||
// Try getting the reason phrase from response
|
||||
if (method_exists($response, 'getReasonPhrase'))
|
||||
{
|
||||
return $response->getReasonPhrase();
|
||||
}
|
||||
|
||||
return 'No error information found in Gitea API response.';
|
||||
}
|
||||
}
|
||||
|
||||
|
1
libraries/vendor_jcb/VDM.Joomla.Github/index.html
Normal file
1
libraries/vendor_jcb/VDM.Joomla.Github/index.html
Normal file
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
155
libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php
Normal file
155
libraries/vendor_jcb/VDM.Joomla.Github/src/Abstraction/Api.php
Normal file
@@ -0,0 +1,155 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Abstraction;
|
||||
|
||||
|
||||
use VDM\Joomla\Github\Utilities\Http;
|
||||
use VDM\Joomla\Github\Utilities\Uri;
|
||||
use VDM\Joomla\Github\Utilities\Response;
|
||||
use VDM\Joomla\Interfaces\Git\ApiInterface;
|
||||
|
||||
|
||||
/**
|
||||
* The Gitea Api
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
abstract class Api implements ApiInterface
|
||||
{
|
||||
/**
|
||||
* The Http class
|
||||
*
|
||||
* @var Http
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Http $http;
|
||||
|
||||
/**
|
||||
* The Uri class
|
||||
*
|
||||
* @var Uri
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Uri $uri;
|
||||
|
||||
/**
|
||||
* The Response class
|
||||
*
|
||||
* @var Response
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected Response $response;
|
||||
|
||||
/**
|
||||
* The Url string
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected ?string $url = null;
|
||||
|
||||
/**
|
||||
* The token string
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected ?string $token = null;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Http $http The http class.
|
||||
* @param Uri $uri The uri class.
|
||||
* @param Response $response The response class.
|
||||
*
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function __construct(Http $http, Uri $uri, Response $response)
|
||||
{
|
||||
$this->http = $http;
|
||||
$this->uri = $uri;
|
||||
$this->response = $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Load/Reload API.
|
||||
*
|
||||
* @param string|null $url The url.
|
||||
* @param token|null $token The token.
|
||||
* @param bool $backup The backup swapping switch.
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function load_(?string $url = null, ?string $token = null, bool $backup = true): void
|
||||
{
|
||||
// we keep the old values
|
||||
// so we can reset after our call
|
||||
// for the rest of the container
|
||||
if ($backup)
|
||||
{
|
||||
if ($url !== null)
|
||||
{
|
||||
$this->url = $this->uri->getUrl();
|
||||
}
|
||||
|
||||
if ($token !== null)
|
||||
{
|
||||
$this->token = $this->http->getToken();
|
||||
}
|
||||
}
|
||||
|
||||
if ($url !== null)
|
||||
{
|
||||
$this->uri->setUrl($url);
|
||||
}
|
||||
|
||||
if ($token !== null)
|
||||
{
|
||||
$this->http->setToken($token);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset to previous toke, url it set
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function reset_(): void
|
||||
{
|
||||
if ($this->url !== null)
|
||||
{
|
||||
$this->uri->setUrl($this->url);
|
||||
$this->url = null;
|
||||
}
|
||||
|
||||
if ($this->token !== null)
|
||||
{
|
||||
$this->http->setToken($this->token);
|
||||
$this->token = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the API url
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public function api()
|
||||
{
|
||||
return $this->uri->api();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,482 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Repository;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface;
|
||||
use VDM\Joomla\Github\Abstraction\Api;
|
||||
|
||||
|
||||
/**
|
||||
* The Github Repository Contents
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Contents extends Api implements ContentsInterface
|
||||
{
|
||||
/**
|
||||
* Get a file from a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string|null $ref Optional. The name of the commit/branch/tag.
|
||||
* Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return mixed
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function get(string $owner, string $repo, string $filepath, ?string $ref = null)
|
||||
{
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/contents/{$filepath}";
|
||||
|
||||
// Get the URI with the specified path.
|
||||
$uri = $this->uri->get($path);
|
||||
|
||||
// Add the ref parameter if provided.
|
||||
if ($ref !== null)
|
||||
{
|
||||
$uri->setVar('ref', $ref);
|
||||
}
|
||||
|
||||
// Send the get request.
|
||||
return $this->response->get(
|
||||
$this->http->raw()->get($uri)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata and contents (if a file) of an entry in a repository,
|
||||
* or a list of entries if a directory.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file or directory path.
|
||||
* @param string|null $ref Optional. The name of the commit/branch/tag.
|
||||
* Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return null|array|object
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function metadata(string $owner, string $repo, string $filepath, ?string $ref = null): null|array|object
|
||||
{
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/contents/{$filepath}";
|
||||
|
||||
// Get the URI with the specified path.
|
||||
$uri = $this->uri->get($path);
|
||||
|
||||
// Add the ref parameter if provided.
|
||||
if ($ref !== null)
|
||||
{
|
||||
$uri->setVar('ref', $ref);
|
||||
}
|
||||
|
||||
// Send the get request.
|
||||
return $this->response->get(
|
||||
$this->http->json()->get($uri)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $content The file content.
|
||||
* @param string $message The commit message.
|
||||
* @param string $branch The branch name. Defaults to the repository's default branch.
|
||||
* @param string|null $authorName The author's name.
|
||||
* @param string|null $authorEmail The author's email.
|
||||
* @param string|null $committerName The committer's name.
|
||||
* @param string|null $committerEmail The committer's email.
|
||||
* @param string|null $newBranch Whether to create a new branch. Defaults to null.
|
||||
* @param string|null $authorDate The author's date.
|
||||
* @param string|null $committerDate The committer's date.
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer. Defaults to null.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function create(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $content,
|
||||
string $message,
|
||||
string $branch = 'master',
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $newBranch = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/contents/{$filepath}";
|
||||
|
||||
// Set the post data
|
||||
$data = new \stdClass();
|
||||
$data->content = base64_encode($content);
|
||||
$data->message = $message;
|
||||
$data->branch = $branch;
|
||||
|
||||
if ($authorName !== null || $authorEmail !== null)
|
||||
{
|
||||
$data->author = new \stdClass();
|
||||
if ($authorName !== null)
|
||||
{
|
||||
$data->author->name = $authorName;
|
||||
}
|
||||
if ($authorEmail !== null)
|
||||
{
|
||||
$data->author->email = $authorEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($committerName !== null || $committerEmail !== null)
|
||||
{
|
||||
$data->committer = new \stdClass();
|
||||
if ($committerName !== null)
|
||||
{
|
||||
$data->committer->name = $committerName;
|
||||
}
|
||||
if ($committerEmail !== null)
|
||||
{
|
||||
$data->committer->email = $committerEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($newBranch !== null)
|
||||
{
|
||||
$data->new_branch = $newBranch;
|
||||
}
|
||||
|
||||
if ($authorDate !== null || $committerDate !== null)
|
||||
{
|
||||
$data->dates = new \stdClass();
|
||||
if ($authorDate !== null)
|
||||
{
|
||||
$data->dates->author = $authorDate;
|
||||
}
|
||||
if ($committerDate !== null)
|
||||
{
|
||||
$data->dates->committer = $committerDate;
|
||||
}
|
||||
}
|
||||
|
||||
if ($signoff !== null)
|
||||
{
|
||||
$data->signoff = $signoff;
|
||||
}
|
||||
|
||||
// Send the post request.
|
||||
return $this->response->get(
|
||||
$this->http->json()->put(
|
||||
$this->uri->get($path), json_encode($data)
|
||||
), 201
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the metadata of all the entries of the root directory.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string|null $ref The name of the commit/branch/tag. Default the repository's default branch (usually master).
|
||||
*
|
||||
* @return array|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function root(string $owner, string $repo, ?string $ref = null): ?array
|
||||
{
|
||||
return $this->metadata($owner, $repo, '', $ref);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $content The file content.
|
||||
* @param string $message The commit message.
|
||||
* @param string $sha The blob SHA of the file.
|
||||
* @param string $branch The branch name. Defaults to the repository's default branch.
|
||||
* @param string|null $authorName The author name. Defaults to the authenticated user.
|
||||
* @param string|null $authorEmail The author email. Defaults to the authenticated user.
|
||||
* @param string|null $committerName The committer name. Defaults to the authenticated user.
|
||||
* @param string|null $committerEmail The committer email. Defaults to the authenticated user.
|
||||
* @param string|null $authorDate The author date.
|
||||
* @param string|null $committerDate The committer date.
|
||||
* @param string|null $fromPath The original file path to move/rename.
|
||||
* @param string|null $newBranch The new branch to create from the specified branch.
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function update(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $content,
|
||||
string $message,
|
||||
string $sha,
|
||||
string $branch = 'master',
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?string $fromPath = null,
|
||||
?string $newBranch = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/contents/{$filepath}";
|
||||
|
||||
// Set the file data.
|
||||
$data = new \stdClass();
|
||||
$data->content = base64_encode($content);
|
||||
$data->message = $message;
|
||||
$data->branch = $branch;
|
||||
$data->sha = $sha;
|
||||
|
||||
if ($authorName !== null || $authorEmail !== null)
|
||||
{
|
||||
$data->author = new \stdClass();
|
||||
|
||||
if ($authorName !== null)
|
||||
{
|
||||
$data->author->name = $authorName;
|
||||
}
|
||||
|
||||
if ($authorEmail !== null)
|
||||
{
|
||||
$data->author->email = $authorEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($committerName !== null || $committerEmail !== null)
|
||||
{
|
||||
$data->committer = new \stdClass();
|
||||
|
||||
if ($committerName !== null)
|
||||
{
|
||||
$data->committer->name = $committerName;
|
||||
}
|
||||
|
||||
if ($committerEmail !== null)
|
||||
{
|
||||
$data->committer->email = $committerEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($authorDate !== null || $committerDate !== null)
|
||||
{
|
||||
$data->dates = new \stdClass();
|
||||
|
||||
if ($authorDate !== null)
|
||||
{
|
||||
$data->dates->author = $authorDate;
|
||||
}
|
||||
|
||||
if ($committerDate !== null)
|
||||
{
|
||||
$data->dates->committer = $committerDate;
|
||||
}
|
||||
}
|
||||
|
||||
if ($fromPath !== null)
|
||||
{
|
||||
$data->from_path = $fromPath;
|
||||
}
|
||||
|
||||
if ($newBranch !== null)
|
||||
{
|
||||
$data->new_branch = $newBranch;
|
||||
}
|
||||
|
||||
if ($signoff !== null)
|
||||
{
|
||||
$data->signoff = $signoff;
|
||||
}
|
||||
|
||||
// Send the put request.
|
||||
return $this->response->get(
|
||||
$this->http->json()->put(
|
||||
$this->uri->get($path),
|
||||
json_encode($data)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string $message The commit message.
|
||||
* @param string $sha The blob SHA of the file.
|
||||
* @param string|null $branch The branch name (optional).
|
||||
* @param string|null $authorName The author name (optional).
|
||||
* @param string|null $authorEmail The author email (optional).
|
||||
* @param string|null $committerName The committer name (optional).
|
||||
* @param string|null $committerEmail The committer email (optional).
|
||||
* @param string|null $authorDate The author date (optional).
|
||||
* @param string|null $committerDate The committer date (optional).
|
||||
* @param string|null $newBranch The new branch name (optional).
|
||||
* @param bool|null $signoff Add a Signed-off-by trailer (optional).
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function delete(
|
||||
string $owner,
|
||||
string $repo,
|
||||
string $filepath,
|
||||
string $message,
|
||||
string $sha,
|
||||
?string $branch = null,
|
||||
?string $authorName = null,
|
||||
?string $authorEmail = null,
|
||||
?string $committerName = null,
|
||||
?string $committerEmail = null,
|
||||
?string $authorDate = null,
|
||||
?string $committerDate = null,
|
||||
?string $newBranch = null,
|
||||
?bool $signoff = null
|
||||
): ?object {
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/contents/{$filepath}";
|
||||
|
||||
// Set the file data.
|
||||
$data = new \stdClass();
|
||||
$data->message = $message;
|
||||
$data->sha = $sha;
|
||||
|
||||
if ($branch !== null) {
|
||||
$data->branch = $branch;
|
||||
}
|
||||
|
||||
if ($authorName !== null || $authorEmail !== null)
|
||||
{
|
||||
$data->author = new \stdClass();
|
||||
|
||||
if ($authorName !== null)
|
||||
{
|
||||
$data->author->name = $authorName;
|
||||
}
|
||||
|
||||
if ($authorEmail !== null)
|
||||
{
|
||||
$data->author->email = $authorEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($committerName !== null || $committerEmail !== null)
|
||||
{
|
||||
$data->committer = new \stdClass();
|
||||
|
||||
if ($committerName !== null)
|
||||
{
|
||||
$data->committer->name = $committerName;
|
||||
}
|
||||
|
||||
if ($committerEmail !== null)
|
||||
{
|
||||
$data->committer->email = $committerEmail;
|
||||
}
|
||||
}
|
||||
|
||||
if ($authorDate !== null || $committerDate !== null)
|
||||
{
|
||||
$data->dates = new \stdClass();
|
||||
|
||||
if ($authorDate !== null)
|
||||
{
|
||||
$data->dates->author = $authorDate;
|
||||
}
|
||||
|
||||
if ($committerDate !== null)
|
||||
{
|
||||
$data->dates->committer = $committerDate;
|
||||
}
|
||||
}
|
||||
|
||||
if ($newBranch !== null)
|
||||
{
|
||||
$data->new_branch = $newBranch;
|
||||
}
|
||||
|
||||
if ($signoff !== null)
|
||||
{
|
||||
$data->signoff = $signoff;
|
||||
}
|
||||
|
||||
// Send the delete request.
|
||||
return $this->response->get(
|
||||
$this->http->json()->delete(
|
||||
$this->uri->get($path), [], null,
|
||||
json_encode($data)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the EditorConfig definitions of a file in a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $filepath The file path.
|
||||
* @param string|null $ref The name of the commit/branch/tag.
|
||||
*
|
||||
* @return string|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function editor(string $owner, string $repo, string $filepath, string $ref = null): ?string
|
||||
{
|
||||
// Not supported in GitHub
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the blob of a repository.
|
||||
*
|
||||
* @param string $owner The owner name.
|
||||
* @param string $repo The repository name.
|
||||
* @param string $sha The SHA hash of the blob.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function blob(string $owner, string $repo, string $sha): ?object
|
||||
{
|
||||
// Build the request path.
|
||||
$path = "/repos/{$owner}/{$repo}/git/blobs/{$sha}";
|
||||
|
||||
// Send the get request.
|
||||
return $this->response->get(
|
||||
$this->http->json()->get(
|
||||
$this->uri->get($path)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Service;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Github\Utilities\Http;
|
||||
use VDM\Joomla\Github\Utilities\Uri;
|
||||
use VDM\Joomla\Github\Utilities\Response;
|
||||
|
||||
|
||||
/**
|
||||
* The Github Utilities Service
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Utilities implements ServiceProviderInterface
|
||||
{
|
||||
/**
|
||||
* Registers the service provider with a DI container.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->alias(Http::class, 'Github.Utilities.Http')
|
||||
->share('Github.Utilities.Http', [$this, 'getHttp'], true);
|
||||
|
||||
$container->alias(Uri::class, 'Github.Utilities.Uri')
|
||||
->share('Github.Utilities.Uri', [$this, 'getUri'], true);
|
||||
|
||||
$container->alias(Response::class, 'Github.Utilities.Response')
|
||||
->share('Github.Utilities.Response', [$this, 'getResponse'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Http class
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Http
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getHttp(Container $container): Http
|
||||
{
|
||||
return new Http();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Uri class
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Uri
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getUri(Container $container): Uri
|
||||
{
|
||||
return new Uri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Response class
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Response
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getResponse(Container $container): Response
|
||||
{
|
||||
return new Response();
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
163
libraries/vendor_jcb/VDM.Joomla.Github/src/Utilities/Http.php
Normal file
163
libraries/vendor_jcb/VDM.Joomla.Github/src/Utilities/Http.php
Normal file
@@ -0,0 +1,163 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Http\Http as JoomlaHttp;
|
||||
use Joomla\Registry\Registry;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* The Github Http
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Http extends JoomlaHttp
|
||||
{
|
||||
/**
|
||||
* The token
|
||||
*
|
||||
* @var string|null
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ?string $_token_; // to avoid collisions (but allow swapping)
|
||||
|
||||
/**
|
||||
* The GitHub API version header
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $apiVersion;
|
||||
|
||||
/**
|
||||
* The GitHub default headers
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $defaultHeaders;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|null $token The Gitea API token.
|
||||
* @param string $version GitHub API Version (e.g. 2022-11-28)
|
||||
*
|
||||
* @since 5.1.1
|
||||
* @throws \InvalidArgumentException
|
||||
**/
|
||||
public function __construct(?string $token = null, string $version = '2022-11-28')
|
||||
{
|
||||
$this->apiVersion = $version;
|
||||
|
||||
$this->defaultHeaders = [
|
||||
'Content-Type' => 'application/json',
|
||||
'Accept' => 'application/vnd.github+json',
|
||||
'X-GitHub-Api-Version' => $this->apiVersion
|
||||
];
|
||||
|
||||
// setup config
|
||||
$config = [
|
||||
'userAgent' => 'JoomlaGitHub/3.0',
|
||||
'headers' => $this->defaultHeaders
|
||||
];
|
||||
|
||||
// add the token if given
|
||||
if (is_string($token) && !empty($token))
|
||||
{
|
||||
$config['headers']['Authorization'] = 'Bearer ' . $token;
|
||||
$this->_token_ = $token;
|
||||
}
|
||||
|
||||
$options = new Registry($config);
|
||||
|
||||
// run parent constructor
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Change the Token.
|
||||
*
|
||||
* @param string $token The Gitea API token.
|
||||
*
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function setToken(string $token): void
|
||||
{
|
||||
// get the current headers
|
||||
$headers = (array) $this->getOption('headers', $this->defaultHeaders);
|
||||
|
||||
if (empty($token))
|
||||
{
|
||||
unset($headers['Authorization']);
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the token
|
||||
$headers['Authorization'] = 'Bearer ' . $token;
|
||||
$this->_token_ = $token;
|
||||
}
|
||||
|
||||
$this->setOption('headers', $headers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Token.
|
||||
*
|
||||
* @return string|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function getToken(): ?string
|
||||
{
|
||||
return $this->_token_ ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Accept header to 'application/vnd.github+json'
|
||||
*
|
||||
* @return static
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function json(): self
|
||||
{
|
||||
$this->setAcceptHeader('application/vnd.github+json');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Accept header to 'application/vnd.github.raw+json'
|
||||
*
|
||||
* @return static
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function raw(): self
|
||||
{
|
||||
$this->setAcceptHeader('application/vnd.github.raw+json');
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set Accept header
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function setAcceptHeader(string $value): void
|
||||
{
|
||||
$headers = (array) $this->getOption('headers', $this->defaultHeaders);
|
||||
$headers['Accept'] = $value;
|
||||
$this->setOption('headers', $headers);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Utilities;
|
||||
|
||||
|
||||
use Joomla\Http\Response as JoomlaResponse;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
|
||||
|
||||
/**
|
||||
* The Github Response
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Response
|
||||
{
|
||||
/**
|
||||
* Process the response and decode it.
|
||||
*
|
||||
* @param JoomlaResponse $response The response.
|
||||
* @param integer $expectedCode The expected "good" code.
|
||||
* @param mixed $default The default if body not have length
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 5.1.1
|
||||
* @throws \DomainException
|
||||
**/
|
||||
public function get(JoomlaResponse $response, int $expectedCode = 200, $default = null)
|
||||
{
|
||||
// Validate the response code.
|
||||
if ($response->code != $expectedCode)
|
||||
{
|
||||
// Decode the error response and throw an exception.
|
||||
$message = $this->error($response);
|
||||
|
||||
throw new \DomainException("Invalid response received from GitHub API. {$message}", $response->code);
|
||||
}
|
||||
|
||||
return $this->body($response, $default);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the response and decode it. (when we have multiple success codes)
|
||||
*
|
||||
* @param JoomlaResponse $response The response.
|
||||
* @param array [$expectedCode => $default] The expected "good" code. and The default if body not have length
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @since 5.1.1
|
||||
* @throws \DomainException
|
||||
**/
|
||||
public function get_(JoomlaResponse $response, array $validate = [200 => null])
|
||||
{
|
||||
// Validate the response code.
|
||||
if (!array_key_exists($response->code, $validate))
|
||||
{
|
||||
// Decode the error response and throw an exception.
|
||||
$message = $this->error($response);
|
||||
|
||||
throw new \DomainException("Invalid response received from GitHub API. {$message}", $response->code);
|
||||
}
|
||||
|
||||
return $this->body($response, $validate[$response->code]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the body from the response
|
||||
*
|
||||
* @param JoomlaResponse $response The response.
|
||||
* @param mixed $default The default if body not have length
|
||||
*
|
||||
* @return mixed
|
||||
* @since 5.1.1
|
||||
**/
|
||||
protected function body(JoomlaResponse $response, $default = null)
|
||||
{
|
||||
$body = method_exists($response, 'getBody')
|
||||
? (string) $response->getBody()
|
||||
: ($response->body ?? null);
|
||||
|
||||
// check that we have a body
|
||||
if ($body !== null && StringHelper::check($body))
|
||||
{
|
||||
if (JsonHelper::check($body))
|
||||
{
|
||||
$body = json_decode((string) $body);
|
||||
|
||||
if (isset($body->content) && isset($body->encoding) && $body->encoding === 'base64')
|
||||
{
|
||||
$body->decoded_content = base64_decode((string) $body->content);
|
||||
}
|
||||
}
|
||||
|
||||
return $body;
|
||||
}
|
||||
|
||||
return $default;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract an error message from a response object.
|
||||
*
|
||||
* @param JoomlaResponse $response The response object.
|
||||
*
|
||||
* @return string The extracted error message, or an empty string.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function error(JoomlaResponse $response): string
|
||||
{
|
||||
// Try to get the raw response body
|
||||
$body = method_exists($response, 'getBody') ? (string) $response->getBody() : '';
|
||||
|
||||
// Try to decode as JSON object
|
||||
$errorData = JsonHelper::check($body) ? json_decode($body) : null;
|
||||
|
||||
if (is_object($errorData))
|
||||
{
|
||||
// GitHub's error structure may have a message and/or an errors array
|
||||
if (!empty($errorData->message)) {
|
||||
$errorMsg = $errorData->message;
|
||||
|
||||
if (!empty($errorData->errors) && is_array($errorData->errors)) {
|
||||
$details = [];
|
||||
|
||||
foreach ($errorData->errors as $err) {
|
||||
if (is_object($err)) {
|
||||
$details[] = trim(
|
||||
($err->resource ?? '') . ' ' .
|
||||
($err->field ?? '') . ' ' .
|
||||
($err->code ?? '')
|
||||
);
|
||||
} else {
|
||||
$details[] = (string) $err;
|
||||
}
|
||||
}
|
||||
|
||||
$errorMsg .= ' (' . implode('; ', array_filter($details)) . ')';
|
||||
}
|
||||
|
||||
return $errorMsg;
|
||||
}
|
||||
|
||||
return json_encode($errorData, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
}
|
||||
|
||||
// Fallback to reason phrase or body
|
||||
if (!empty($body))
|
||||
{
|
||||
return $body;
|
||||
}
|
||||
|
||||
return method_exists($response, 'getReasonPhrase')
|
||||
? $response->getReasonPhrase()
|
||||
: 'No error information found in GitHub API response.';
|
||||
}
|
||||
}
|
||||
|
169
libraries/vendor_jcb/VDM.Joomla.Github/src/Utilities/Uri.php
Normal file
169
libraries/vendor_jcb/VDM.Joomla.Github/src/Utilities/Uri.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Github\Utilities;
|
||||
|
||||
|
||||
use Joomla\Uri\Uri as JoomlaUri;
|
||||
|
||||
|
||||
/**
|
||||
* The Github Uri
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Uri
|
||||
{
|
||||
/**
|
||||
* The api endpoint
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private string $endpoint;
|
||||
|
||||
/**
|
||||
* The api version
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private string $version;
|
||||
|
||||
/**
|
||||
* The api URL
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private string $url;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $url URL to the github system
|
||||
* example: https://api.github.com
|
||||
* @param string $endpoint Endpoint to the gitea system
|
||||
* @param string $version Version to the gitea system
|
||||
*
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function __construct(
|
||||
string $url = 'https://api.github.com',
|
||||
string $endpoint = '',
|
||||
string $version = 'v3')
|
||||
{
|
||||
// set the API details
|
||||
$this->setUrl($url);
|
||||
//$this->setEndpoint($endpoint);
|
||||
//$this->setVersion($version);
|
||||
}
|
||||
|
||||
/**
|
||||
* Method to build and return a full request URL for the request. This method will
|
||||
* add appropriate pagination details if necessary and also prepend the API url
|
||||
* to have a complete URL for the request.
|
||||
*
|
||||
* @param string $path URL to inflect
|
||||
*
|
||||
* @return JoomlaUri
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function get(string $path): JoomlaUri
|
||||
{
|
||||
// GitHub API does not use version in URL (normally passed in Accept headers)
|
||||
// But we maintain compatibility with existing interface
|
||||
$uri = new JoomlaUri($this->api() . ltrim($path, '/'));
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the full API URL
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function api(): string
|
||||
{
|
||||
// Ensure trailing slash on base URL
|
||||
return rtrim($this->url, '/') . '/';
|
||||
/**
|
||||
// GitHub typically does not use endpoint/version in URL
|
||||
// But to preserve interface, we include them conditionally
|
||||
$segments = [];
|
||||
|
||||
if (!empty($this->endpoint))
|
||||
{
|
||||
$segments[] = trim($this->endpoint, '/');
|
||||
}
|
||||
|
||||
if (!empty($this->version))
|
||||
{
|
||||
$segments[] = trim($this->version, '/');
|
||||
}
|
||||
|
||||
return $base . (empty($segments) ? '' : implode('/', $segments) . '/');
|
||||
**/
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the URL of the API
|
||||
*
|
||||
* @param string $url URL to your github system
|
||||
* example: https://api.github.com
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function setUrl(string $url)
|
||||
{
|
||||
$this->url = $url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the URL of the API
|
||||
*
|
||||
* @return string|null
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function getUrl(): ?string
|
||||
{
|
||||
return $this->url ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the endpoint of the API
|
||||
*
|
||||
* @param string $endpoint endpoint to your github API
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
private function setEndpoint(string $endpoint)
|
||||
{
|
||||
$this->endpoint = $endpoint;
|
||||
}
|
||||
**/
|
||||
|
||||
/**
|
||||
* Set the version of the API
|
||||
*
|
||||
* @param string $version version to your github API
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
private function setVersion($version)
|
||||
{
|
||||
$this->version = $version;
|
||||
}
|
||||
**/
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -13,7 +13,7 @@ namespace VDM\Joomla\Abstraction;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\Database\DatabaseInterface;
|
||||
use Joomla\Database\DatabaseInterface as JoomlaDatabase;
|
||||
use VDM\Joomla\Utilities\Component\Helper;
|
||||
|
||||
|
||||
@@ -27,17 +27,10 @@ abstract class Database
|
||||
/**
|
||||
* Database object to query local DB
|
||||
*
|
||||
* @var JoomlaDatabase
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected $db;
|
||||
|
||||
/**
|
||||
* Core Component Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected string $table;
|
||||
protected JoomlaDatabase $db;
|
||||
|
||||
/**
|
||||
* Date format to return
|
||||
@@ -47,67 +40,109 @@ abstract class Database
|
||||
*/
|
||||
protected string $dateFormat = 'Y-m-d H:i:s';
|
||||
|
||||
/**
|
||||
* Current component code name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $componentCode;
|
||||
|
||||
/**
|
||||
* Core Component Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected string $table;
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @throws \Exception
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct()
|
||||
public function __construct(?JoomlaDatabase $db = null)
|
||||
{
|
||||
$this->db = Factory::getContainer()->get(DatabaseInterface::class);
|
||||
$this->db = $db ?: Factory::getContainer()->get(JoomlaDatabase::class);
|
||||
|
||||
// set the component table
|
||||
$this->table = '#__' . Helper::getCode();
|
||||
$this->componentCode = Helper::getCode();
|
||||
$this->table = '#__' . $this->componentCode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a value based on data type
|
||||
* Safely quote a value for database use, preserving data integrity.
|
||||
*
|
||||
* @param mixed $value The value to set
|
||||
* - Native ints/floats passed as-is
|
||||
* - Clean integer strings are cast to int
|
||||
* - Clean float strings are cast to float
|
||||
* - Scientific notation is quoted to preserve original form
|
||||
* - Leading-zero integers are quoted
|
||||
* - Dates are formatted and quoted
|
||||
* - Booleans are converted to TRUE/FALSE
|
||||
* - Null is converted to NULL
|
||||
* - All else is quoted with Joomla's db quote
|
||||
*
|
||||
* @param mixed $value The value to quote.
|
||||
*
|
||||
* @return mixed
|
||||
* @since 3.2.0
|
||||
**/
|
||||
*/
|
||||
protected function quote($value)
|
||||
{
|
||||
// NULL handling
|
||||
if ($value === null)
|
||||
{
|
||||
return 'NULL';
|
||||
}
|
||||
|
||||
if (is_numeric($value))
|
||||
// DateTime handling
|
||||
if ($value instanceof \DateTimeInterface)
|
||||
{
|
||||
// If the value is a numeric string (e.g., "0123"), treat it as a string to preserve the format
|
||||
if (is_string($value) && ltrim($value, '0') !== $value)
|
||||
return $this->db->quote($value->format($this->getDateFormat()));
|
||||
}
|
||||
|
||||
// Native numeric types
|
||||
if (is_int($value) || is_float($value))
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Stringified numeric values
|
||||
if (is_string($value) && is_numeric($value))
|
||||
{
|
||||
// Case 1: Leading-zero integers like "007"
|
||||
if ($value[0] === '0' && strlen($value) > 1 && ctype_digit($value))
|
||||
{
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
if (filter_var($value, FILTER_VALIDATE_INT))
|
||||
// Case 2: Scientific notation - preserve exact format
|
||||
if (stripos($value, 'e') !== false)
|
||||
{
|
||||
return (int) $value;
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
if (filter_var($value, FILTER_VALIDATE_FLOAT))
|
||||
// Case 3: Decimal float string (not scientific)
|
||||
if (str_contains($value, '.'))
|
||||
{
|
||||
return (float) $value;
|
||||
}
|
||||
|
||||
// Case 4: Pure integer string
|
||||
if (ctype_digit($value))
|
||||
{
|
||||
return (int) $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Handle boolean values
|
||||
// Boolean handling
|
||||
if (is_bool($value))
|
||||
{
|
||||
return $value ? 'TRUE' : 'FALSE';
|
||||
}
|
||||
|
||||
// For date and datetime values
|
||||
if ($value instanceof \DateTime)
|
||||
{
|
||||
return $this->db->quote($value->format($this->getDateFormat()));
|
||||
}
|
||||
|
||||
// For other types of values, quote as string
|
||||
// Everything else
|
||||
return $this->db->quote($value);
|
||||
}
|
||||
|
||||
@@ -128,17 +163,6 @@ abstract class Database
|
||||
}
|
||||
|
||||
return $table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the date format to return in the quote
|
||||
*
|
||||
* @return string
|
||||
* @since 5.0.2
|
||||
**/
|
||||
protected function getDateFormat(): string
|
||||
{
|
||||
return $this->dateFormat;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -14,11 +14,12 @@ namespace VDM\Joomla\Abstraction;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface as Config;
|
||||
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface as Contents;
|
||||
use VDM\Joomla\Componentbuilder\Network\Resolve;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
use VDM\Joomla\Interfaces\Git\ApiInterface as Api;
|
||||
use VDM\Joomla\Utilities\FileHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
@@ -41,7 +42,7 @@ abstract class Grep implements GrepInterface
|
||||
* The local path
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public ?string $path;
|
||||
|
||||
@@ -49,7 +50,7 @@ abstract class Grep implements GrepInterface
|
||||
* All approved paths
|
||||
*
|
||||
* @var array|null
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
**/
|
||||
public ?array $paths;
|
||||
|
||||
@@ -61,11 +62,19 @@ abstract class Grep implements GrepInterface
|
||||
**/
|
||||
protected ?string $target = null;
|
||||
|
||||
/**
|
||||
* The Grep target [entity]
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.4
|
||||
**/
|
||||
protected string $entity;
|
||||
|
||||
/**
|
||||
* The target branch field name ['read_branch', 'write_branch']
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
**/
|
||||
protected string $branch_field = 'read_branch';
|
||||
|
||||
@@ -73,7 +82,7 @@ abstract class Grep implements GrepInterface
|
||||
* Order of global search
|
||||
*
|
||||
* @var array
|
||||
* @since 3.2.1
|
||||
* @since 3.2.1
|
||||
**/
|
||||
protected array $order = ['local', 'remote'];
|
||||
|
||||
@@ -81,7 +90,7 @@ abstract class Grep implements GrepInterface
|
||||
* The target default branch name
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
**/
|
||||
protected ?string $branch_name = null;
|
||||
|
||||
@@ -89,15 +98,23 @@ abstract class Grep implements GrepInterface
|
||||
* The VDM global API base
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.4
|
||||
* @since 5.0.4
|
||||
**/
|
||||
protected string $api_base = '//git.vdm.dev/';
|
||||
|
||||
/**
|
||||
* The Config Class.
|
||||
*
|
||||
* @var Config
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Config $config;
|
||||
|
||||
/**
|
||||
* Gitea Repository Contents
|
||||
*
|
||||
* @var Contents
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected Contents $contents;
|
||||
|
||||
@@ -110,18 +127,18 @@ abstract class Grep implements GrepInterface
|
||||
protected Resolve $resolve;
|
||||
|
||||
/**
|
||||
* The ConfigInterface Class.
|
||||
* The Tracker Class.
|
||||
*
|
||||
* @var Config
|
||||
* @var Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Config $config;
|
||||
protected Tracker $tracker;
|
||||
|
||||
/**
|
||||
* Joomla Application object
|
||||
*
|
||||
* @var CMSApplication
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
**/
|
||||
protected CMSApplication $app;
|
||||
|
||||
@@ -131,6 +148,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param Config $config The Config Class.
|
||||
* @param Contents $contents The Contents Class.
|
||||
* @param Resolve $resolve The Resolve Class.
|
||||
* @param Tracker $tracker The Tracker Class.
|
||||
* @param array $paths The approved paths
|
||||
* @param string|null $path The local path
|
||||
* @param CMSApplication|null $app The Application Class.
|
||||
@@ -138,12 +156,14 @@ abstract class Grep implements GrepInterface
|
||||
* @since 3.2.1
|
||||
*/
|
||||
public function __construct(Config $config, Contents $contents,
|
||||
Resolve $resolve, array $paths, ?string $path = null,
|
||||
?CMSApplication $app = null)
|
||||
Resolve $resolve, Tracker $tracker, array $paths,
|
||||
?string $path = null, ?CMSApplication $app = null)
|
||||
{
|
||||
$this->entity = $config->getTable();
|
||||
$this->config = $config;
|
||||
$this->contents = $contents;
|
||||
$this->resolve = $resolve;
|
||||
$this->tracker = $tracker;
|
||||
|
||||
$this->paths = $paths;
|
||||
$this->path = $path;
|
||||
@@ -161,7 +181,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param object|null $repo The repository object to search. If null, all repos will be searched.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function get(string $guid, ?array $order = null, ?object $repo = null): ?object
|
||||
{
|
||||
@@ -238,7 +258,7 @@ abstract class Grep implements GrepInterface
|
||||
// Get remote index
|
||||
$this->indexRemote($path);
|
||||
|
||||
if (isset($path->index) && is_object($path->index))
|
||||
if (is_array($path->index ?? null) && is_object($path->index[$this->entity] ?? null))
|
||||
{
|
||||
$powers[] = $path;
|
||||
}
|
||||
@@ -272,7 +292,7 @@ abstract class Grep implements GrepInterface
|
||||
// Get remote index
|
||||
$this->indexRemote($path);
|
||||
|
||||
if (isset($path->index) && is_object($path->index))
|
||||
if (is_array($path->index ?? null) && is_object($path->index[$this->entity] ?? null))
|
||||
{
|
||||
return $path;
|
||||
}
|
||||
@@ -287,7 +307,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $guid The unique identifier for the repo.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function getRemoteIndex(string $guid): ?object
|
||||
{
|
||||
@@ -306,15 +326,26 @@ abstract class Grep implements GrepInterface
|
||||
// Get remote index
|
||||
$this->indexRemote($path);
|
||||
|
||||
if (isset($path->index) && is_object($path->index))
|
||||
if (is_array($path->index ?? null) && is_object($path->index[$this->entity] ?? null))
|
||||
{
|
||||
return $path->index;
|
||||
return $path->index[$this->entity];
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the network target name
|
||||
*
|
||||
* @return string|null
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getNetworkTarget(): ?string
|
||||
{
|
||||
return $this->target ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item exists in any repo or in a specific repo.
|
||||
*
|
||||
@@ -323,7 +354,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param array|null $order The order of the targets to check. If null, the default order will be used.
|
||||
*
|
||||
* @return bool True if the item exists, false otherwise.
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function exists(string $guid, ?object $repo = null, ?array $order = null): bool
|
||||
{
|
||||
@@ -343,7 +374,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $field The field to use to get the branch name from the data set
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function setBranchField(string $field): void
|
||||
{
|
||||
@@ -356,7 +387,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string|null $name The default branch to use if no name could be found
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function setBranchDefaultName(?string $name): void
|
||||
{
|
||||
@@ -369,7 +400,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $indexPath The repository index path
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function setIndexPath(string $indexPath): void
|
||||
{
|
||||
@@ -388,12 +419,12 @@ abstract class Grep implements GrepInterface
|
||||
* @param string|null $token The token for authentication (can be null).
|
||||
*
|
||||
* @return void
|
||||
* @since 5.0.4
|
||||
* @since 5.0.4
|
||||
*/
|
||||
public function loadApi(Api $api, ?string $base, ?string $token): void
|
||||
{
|
||||
// Determine the token to use based on the base URL
|
||||
if ($base && strpos($base, $this->api_base) !== false)
|
||||
if ($base && strpos($base. '/', $this->api_base) !== false)
|
||||
{
|
||||
// If base contains $this->api_base = https://git.vdm.dev/, use the token as is
|
||||
$tokenToUse = $token;
|
||||
@@ -418,10 +449,55 @@ abstract class Grep implements GrepInterface
|
||||
* @param string|null $base Base URL
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
abstract protected function setRemoteIndexMessage(string $message, string $path, string $repository, string $organisation, ?string $base): void;
|
||||
|
||||
/**
|
||||
* Injects metadata SHA into the power params object.
|
||||
*
|
||||
* @param object $power The object to modify
|
||||
* @param object $path The repository path
|
||||
* @param string $targetPath The target path inside the repo
|
||||
* @param string $branch The branch to use
|
||||
* @param string $sourceKey The key to set inside params->source
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function setRepoItemSha(object &$power, object $path,
|
||||
string $targetPath, string $branch, string $sourceKey): void
|
||||
{
|
||||
try {
|
||||
$meta = $this->contents->metadata(
|
||||
$path->organisation,
|
||||
$path->repository,
|
||||
$targetPath,
|
||||
$branch
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$meta = null;
|
||||
}
|
||||
|
||||
if ($meta === null || !isset($meta->sha))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($power->params) || !is_object($power->params))
|
||||
{
|
||||
$power->params = (object) ['source' => [$sourceKey => $meta->sha]];
|
||||
return;
|
||||
}
|
||||
|
||||
if (!isset($power->params->source) || !is_array($power->params->source))
|
||||
{
|
||||
$power->params->source = [];
|
||||
}
|
||||
|
||||
$power->params->source[$sourceKey] = $meta->sha;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get function name
|
||||
*
|
||||
@@ -429,7 +505,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $type The type of function name
|
||||
*
|
||||
* @return string|null
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function getFunctionName(string $name, string $type = 'search'): ?string
|
||||
{
|
||||
@@ -446,7 +522,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $repo The repository object to check against.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function searchSingleRepo(string $guid, array $order, object $repo): ?object
|
||||
{
|
||||
@@ -472,7 +548,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $repo The repository object to check against.
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function searchAllRepos(string $guid, array $order): ?object
|
||||
{
|
||||
@@ -499,7 +575,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param array $order The order of the targets to check.
|
||||
*
|
||||
* @return bool True if the item exists, false otherwise.
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function itemExistsInRepo(string $guid, object $repo, array $order): bool
|
||||
{
|
||||
@@ -520,7 +596,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param array $order The order of the targets to check.
|
||||
*
|
||||
* @return bool True if the item exists, false otherwise.
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function itemExistsInAllRepos(string $guid, array $order): bool
|
||||
{
|
||||
@@ -545,7 +621,7 @@ abstract class Grep implements GrepInterface
|
||||
* Get the branch field
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getBranchField(): string
|
||||
{
|
||||
@@ -556,7 +632,7 @@ abstract class Grep implements GrepInterface
|
||||
* Get the branch default name
|
||||
*
|
||||
* @return string|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getBranchDefaultName(): ?string
|
||||
{
|
||||
@@ -569,7 +645,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $item The item path
|
||||
*
|
||||
* @return string|null
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getBranchName(object $item): ?string
|
||||
{
|
||||
@@ -583,7 +659,7 @@ abstract class Grep implements GrepInterface
|
||||
* Get the index path
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getIndexPath(): string
|
||||
{
|
||||
@@ -591,14 +667,14 @@ abstract class Grep implements GrepInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings path
|
||||
* Get the settings name
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getSettingsPath(): string
|
||||
protected function getSettingsName(): string
|
||||
{
|
||||
return $this->config->getSettingsPath();
|
||||
return $this->config->getSettingsName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -612,6 +688,28 @@ abstract class Grep implements GrepInterface
|
||||
return $this->config->getGuidField();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get GUID field
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getItemReadmeName(): string
|
||||
{
|
||||
return $this->config->getItemReadmeName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Has item readme
|
||||
*
|
||||
* @return bool
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function hasItemReadme(): bool
|
||||
{
|
||||
return $this->config->hasItemReadme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if an item exists in a specific repo and target.
|
||||
*
|
||||
@@ -620,7 +718,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $target The target to check within the repo.
|
||||
*
|
||||
* @return bool True if the item exists, false otherwise.
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function itemExists(string $guid, object &$repo, string $target): bool
|
||||
{
|
||||
@@ -644,7 +742,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $guid The global unique id of the item
|
||||
*
|
||||
* @return object|null return path object
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function existsLocally(string $guid): ?object
|
||||
{
|
||||
@@ -672,7 +770,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string $guid The global unique id of the item
|
||||
*
|
||||
* @return object|null return path object
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function existsRemotely(string $guid): ?object
|
||||
{
|
||||
@@ -701,11 +799,12 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $path The path object
|
||||
*
|
||||
* @return bool true if it exists
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function existsLocal(string $guid, object $path): bool
|
||||
{
|
||||
if (!empty($path->local) && isset($path->local->{$guid}))
|
||||
if (is_array($path->local ?? null) && is_object($path->local[$this->entity] ?? null) &&
|
||||
isset($path->local[$this->entity]->{$guid}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -720,11 +819,12 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $path The path object
|
||||
*
|
||||
* @return bool true if it exists
|
||||
* @since 3.2.2
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function existsRemote(string $guid, object $path): bool
|
||||
{
|
||||
if (!empty($path->index) && isset($path->index->{$guid}))
|
||||
if (is_array($path->index ?? null) && is_object($path->index[$this->entity] ?? null) &&
|
||||
isset($path->index[$this->entity]->{$guid}))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -738,25 +838,44 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $path The repository path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function indexRemote(object &$path): void
|
||||
{
|
||||
if (isset($path->index))
|
||||
if (is_array($path->index ?? null) && isset($path->index[$this->entity]))
|
||||
{
|
||||
return; // already set
|
||||
}
|
||||
|
||||
if (!is_array($path->index ?? null))
|
||||
{
|
||||
$path->index = [];
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
// set the target system
|
||||
$target = $path->target ?? 'gitea';
|
||||
$this->contents->setTarget($target);
|
||||
|
||||
// load the base and token if set
|
||||
$this->loadApi($this->contents, $path->base ?? null, $path->token ?? null);
|
||||
$path->index = $this->contents->get($path->organisation, $path->repository, $this->getIndexPath(), $this->getBranchName($path));
|
||||
$this->loadApi(
|
||||
$this->contents,
|
||||
$target === 'gitea' ? ($path->base ?? null) : null,
|
||||
$path->token ?? null
|
||||
);
|
||||
|
||||
$path->index[$this->entity] = $this->contents->get($path->organisation, $path->repository, $this->getIndexPath(), $this->getBranchName($path));
|
||||
}
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$path->index = null;
|
||||
$this->setRemoteIndexMessage($e->getMessage(), $path->path, $path->repository, $path->organisation, $path->base ?? null);
|
||||
$path->index[$this->entity] = null;
|
||||
|
||||
// only when searching (read_branch) do we show this error message
|
||||
if ($this->getBranchField() === 'read_branch')
|
||||
{
|
||||
$this->setRemoteIndexMessage($e->getMessage(), $path->path, $path->repository, $path->organisation, $path->base ?? null);
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
@@ -771,45 +890,53 @@ abstract class Grep implements GrepInterface
|
||||
* @param object $path The repository path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function indexLocal(object &$path): void
|
||||
{
|
||||
if (isset($path->local) || !isset($path->full_path))
|
||||
if (is_array($path->local ?? null) && isset($path->local[$this->entity]))
|
||||
{
|
||||
return;
|
||||
return; // already set
|
||||
}
|
||||
|
||||
if (!is_array($path->local ?? null))
|
||||
{
|
||||
$path->local = [];
|
||||
}
|
||||
|
||||
if (($content = FileHelper::getContent($path->full_path . '/' . $this->getIndexPath(), null)) !== null &&
|
||||
JsonHelper::check($content))
|
||||
{
|
||||
$path->local = json_decode($content);
|
||||
$path->local[$this->entity] = json_decode($content);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$path->local = null;
|
||||
$path->local[$this->entity] = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set path details
|
||||
*
|
||||
* @return void
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function initializeInstances(): void
|
||||
{
|
||||
if (is_array($this->paths) && $this->paths !== [])
|
||||
{
|
||||
$network_target = $this->getNetworkTarget();
|
||||
foreach ($this->paths as $n => &$path)
|
||||
{
|
||||
if (isset($path->organisation) && strlen($path->organisation) > 1 &&
|
||||
isset($path->repository) && strlen($path->repository) > 1)
|
||||
{
|
||||
// resolve API if needed
|
||||
if (!empty($path->base))
|
||||
$target = $path->target ?? 'gitea';
|
||||
|
||||
// resolve API if a gitea (core) endpoint
|
||||
if (!empty($path->base) && $target === 'gitea')
|
||||
{
|
||||
$this->resolve->api($this->target ?? $path->repository, $path->base, $path->organisation, $path->repository);
|
||||
$this->resolve->api($network_target ?? $path->repository, $path->base, $path->organisation, $path->repository);
|
||||
}
|
||||
|
||||
// build the path
|
||||
@@ -827,7 +954,7 @@ abstract class Grep implements GrepInterface
|
||||
}
|
||||
|
||||
// set local path
|
||||
if ($this->path && Folder::exists($this->path . '/' . $path->path))
|
||||
if ($this->path && is_dir($this->path . '/' . $path->path))
|
||||
{
|
||||
$path->full_path = $this->path . '/' . $path->path;
|
||||
}
|
||||
@@ -849,7 +976,7 @@ abstract class Grep implements GrepInterface
|
||||
* @param string|null $branch The repository branch name
|
||||
*
|
||||
* @return mixed
|
||||
* @since 3.2.0
|
||||
* @since 3.2.0
|
||||
*/
|
||||
protected function loadRemoteFile(string $organisation, string $repository, string $path, ?string $branch)
|
||||
{
|
||||
@@ -860,7 +987,7 @@ abstract class Grep implements GrepInterface
|
||||
catch (\Exception $e)
|
||||
{
|
||||
$this->app->enqueueMessage(
|
||||
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $path, $e->getMessage()),
|
||||
Text::sprintf('COM_COMPONENTBUILDER_PFILE_AT_BSSSSB_GAVE_THE_FOLLOWING_ERRORBR_SP', $this->contents->api(), $organisation, $repository, $path, $e->getMessage()),
|
||||
'Error'
|
||||
);
|
||||
|
||||
|
@@ -62,11 +62,11 @@ abstract class Model implements ModelInterface
|
||||
*
|
||||
* @param Table $table The search table object.
|
||||
* @param string|null $tableName The table
|
||||
* @param bool|null $allowEmpty The switch to control the behaviour of empty values (default true)
|
||||
* @param bool|null $allowEmpty The switch to control the behaviour of empty values (default true)
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Table $table, ?string $tableName = null, bool $allowEmpty = null)
|
||||
public function __construct(Table $table, ?string $tableName = null, ?bool $allowEmpty = null)
|
||||
{
|
||||
$this->table = $table;
|
||||
if ($tableName !== null)
|
||||
|
@@ -96,29 +96,29 @@ abstract class Base implements BaseInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the settings path
|
||||
* Set the settings file name
|
||||
*
|
||||
* @param string $settingsPath The repository settings path
|
||||
* @param string $settingsName The repository settings name
|
||||
*
|
||||
* @return self
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function setSettingsPath(string $settingsPath): self
|
||||
public function setSettingsName(string $settingsName): self
|
||||
{
|
||||
$this->config->setSettingsPath($settingsPath);
|
||||
$this->config->setSettingsName($settingsName);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings path
|
||||
* Get the settings file name
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function getSettingsPath(): string
|
||||
public function getSettingsName(): string
|
||||
{
|
||||
return $this->config->getSettingsPath();
|
||||
return $this->config->getSettingsName();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -189,6 +189,28 @@ abstract class Base implements BaseInterface
|
||||
return $this->config->getSrcPath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field names of the files in the entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getFiles(): array
|
||||
{
|
||||
return $this->config->getFiles();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field names of the folders in the entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getFolders(): array
|
||||
{
|
||||
return $this->config->getFolders();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map
|
||||
*
|
||||
@@ -200,6 +222,17 @@ abstract class Base implements BaseInterface
|
||||
return $this->config->getMap();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the [direct] entities/children of this entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getChildren(): array
|
||||
{
|
||||
return $this->config->getChildren();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table title name field
|
||||
*
|
||||
@@ -233,6 +266,39 @@ abstract class Base implements BaseInterface
|
||||
return $this->config->getMainReadmePath();
|
||||
}
|
||||
|
||||
/**
|
||||
* Has main readme
|
||||
*
|
||||
* @return bool
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function hasMainReadme(): bool
|
||||
{
|
||||
return $this->config->hasMainReadme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item readme path
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getItemReadmeName(): string
|
||||
{
|
||||
return $this->config->getItemReadmeName();
|
||||
}
|
||||
|
||||
/**
|
||||
* Has item readme
|
||||
*
|
||||
* @return bool
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function hasItemReadme(): bool
|
||||
{
|
||||
return $this->config->hasItemReadme();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get Prefix Key
|
||||
*
|
||||
@@ -274,7 +340,7 @@ abstract class Base implements BaseInterface
|
||||
{
|
||||
$this->{$methodName}($item, $power);
|
||||
}
|
||||
else
|
||||
elseif (!isset($power[$key]))
|
||||
{
|
||||
$power[$key] = $item->{$map} ?? null;
|
||||
}
|
||||
@@ -350,12 +416,12 @@ abstract class Base implements BaseInterface
|
||||
*/
|
||||
protected function index_map_IndexSettingsPath(object $item): string
|
||||
{
|
||||
$src_path = $this->getSrcPath();
|
||||
$settings_path = $this->getSettingsPath();
|
||||
$index_path = $this->index_map_IndexPath($item);
|
||||
$settings_name = $this->getSettingsName();
|
||||
|
||||
$key = $this->index_map_IndexGUID($item);
|
||||
|
||||
return "{$src_path}/{$key}/{$settings_path}";
|
||||
return !empty($settings_name)
|
||||
? "{$index_path}/{$settings_name}"
|
||||
: $index_path;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -369,12 +435,28 @@ abstract class Base implements BaseInterface
|
||||
protected function index_map_IndexPath(object $item): string
|
||||
{
|
||||
$src_path = $this->getSrcPath();
|
||||
|
||||
$key = $this->index_map_IndexGUID($item);
|
||||
|
||||
return "{$src_path}/{$key}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item readme path for the index values
|
||||
*
|
||||
* @param object $item
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function index_map_IndexReadmePath(object $item): string
|
||||
{
|
||||
$index_path = $this->index_map_IndexPath($item);
|
||||
$readme = $this->getItemReadmeName();
|
||||
|
||||
return !empty($readme)
|
||||
? "{$index_path}/{$readme}"
|
||||
: "{$index_path}.md";
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the item [POWER KEY] for the index values
|
||||
*
|
||||
@@ -387,7 +469,6 @@ abstract class Base implements BaseInterface
|
||||
{
|
||||
$prefix_key = $this->getPrefixKey();
|
||||
$suffix_key = $this->getSuffixKey();
|
||||
|
||||
$key = $this->index_map_IndexGUID($item);
|
||||
$key = str_replace('-', '_', $key);
|
||||
|
||||
@@ -405,7 +486,8 @@ abstract class Base implements BaseInterface
|
||||
protected function index_map_IndexGUID(object $item): string
|
||||
{
|
||||
$guid_field = $this->getGuidField();
|
||||
return $item->{$guid_field} ?? 'error';
|
||||
|
||||
return $item->{$guid_field} ?? $item->guid ?? 'missing-guid';
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,7 @@ use VDM\Joomla\Interfaces\Remote\ConfigInterface;
|
||||
/**
|
||||
* Remote Base Config Shared by get and set methods
|
||||
*
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
abstract class Config implements ConfigInterface
|
||||
{
|
||||
@@ -27,7 +27,7 @@ abstract class Config implements ConfigInterface
|
||||
* The Table Class.
|
||||
*
|
||||
* @var Table
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Table $core;
|
||||
|
||||
@@ -53,7 +53,7 @@ abstract class Config implements ConfigInterface
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $prefix_key = 'Super---';
|
||||
protected string $prefix_key = '';
|
||||
|
||||
/**
|
||||
* Suffix Key
|
||||
@@ -61,16 +61,24 @@ abstract class Config implements ConfigInterface
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $suffix_key = '---Power';
|
||||
protected string $suffix_key = '';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = 'README.md';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $item_readme_name = 'README.md';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
@@ -83,23 +91,23 @@ abstract class Config implements ConfigInterface
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $src_path = 'src';
|
||||
|
||||
/**
|
||||
* The item settings file path (item data)
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $settings_path = 'item.json';
|
||||
protected string $settings_name = 'item.json';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $guid_field = 'guid';
|
||||
|
||||
@@ -107,9 +115,33 @@ abstract class Config implements ConfigInterface
|
||||
* The ignore fields
|
||||
*
|
||||
* @var array
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $ignore = [];
|
||||
protected array $ignore = ['access'];
|
||||
|
||||
/**
|
||||
* The files (to map target files to move in an entity)
|
||||
*
|
||||
* Use a pipe in the name to denote
|
||||
* subform location of the value
|
||||
* format: [field_name, field_name|subfrom_key]
|
||||
*
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $files = [];
|
||||
|
||||
/**
|
||||
* The folders (to map target folders to move in an entity)
|
||||
*
|
||||
* Use a pipe in the name to denote
|
||||
* subform location of the value
|
||||
* format: [field_name, field_name|subfrom_key]
|
||||
*
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $folders = [];
|
||||
|
||||
/**
|
||||
* The item map
|
||||
@@ -119,34 +151,45 @@ abstract class Config implements ConfigInterface
|
||||
*/
|
||||
protected array $map = [];
|
||||
|
||||
/**
|
||||
* The direct entities/children of this entity
|
||||
*
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $children = [];
|
||||
|
||||
/**
|
||||
* The index map
|
||||
* must always have: [name,path,guid]
|
||||
* must always have: [name,path,settings,guid]
|
||||
* you can add more
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected array $index_map = [
|
||||
'name' => 'index_map_IndexName',
|
||||
'path' => 'index_map_IndexPath',
|
||||
'settings' => 'index_map_IndexSettingsPath',
|
||||
'guid' => 'index_map_IndexGUID'
|
||||
];
|
||||
|
||||
/**
|
||||
* The index header
|
||||
* mapping the index map to a table
|
||||
* must always have: [name,path,guid,local]
|
||||
* must always have: [name,path,settings,guid,local]
|
||||
* with [name] always first
|
||||
* with [path,guid,local] always last
|
||||
* with [path,settings,guid,local] always last
|
||||
* you can add more in between
|
||||
*
|
||||
* @var array
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $index_header = [
|
||||
'name',
|
||||
// from here you can add more
|
||||
'path',
|
||||
'settings',
|
||||
'guid',
|
||||
'local'
|
||||
];
|
||||
@@ -157,19 +200,14 @@ abstract class Config implements ConfigInterface
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected array $placeholders = [
|
||||
'[['.'[NamespacePrefix]]]' => 'VDM',
|
||||
'[['.'[ComponentNamespace]]]' => 'Componentbuilder',
|
||||
'[['.'[Component]]]' => 'Componentbuilder',
|
||||
'[['.'[component]]]' => 'componentbuilder'
|
||||
];
|
||||
protected array $placeholders = [];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Table $core The Core Table Class.
|
||||
*
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(Table $core)
|
||||
{
|
||||
@@ -180,7 +218,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get core placeholders
|
||||
*
|
||||
* @return array
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getPlaceholders(): array
|
||||
{
|
||||
@@ -240,29 +278,29 @@ abstract class Config implements ConfigInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the settings path
|
||||
* Set the settings file name
|
||||
*
|
||||
* @param string $settingsPath The repository settings path
|
||||
* @param string $settingsName The repository settings path
|
||||
*
|
||||
* @return self
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function setSettingsPath(string $settingsPath): self
|
||||
public function setSettingsName(string $settingsName): self
|
||||
{
|
||||
$this->settings_path = $settingsPath;
|
||||
$this->settings_name = $settingsName;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the settings path
|
||||
* Get the settings file name
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function getSettingsPath(): string
|
||||
public function getSettingsName(): string
|
||||
{
|
||||
return $this->settings_path;
|
||||
return $this->settings_name;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -293,7 +331,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get index map
|
||||
*
|
||||
* @return array
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getIndexMap(): array
|
||||
{
|
||||
@@ -304,7 +342,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get index header
|
||||
*
|
||||
* @return array
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getIndexHeader(): array
|
||||
{
|
||||
@@ -315,7 +353,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get src path
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getSrcPath(): string
|
||||
{
|
||||
@@ -326,13 +364,68 @@ abstract class Config implements ConfigInterface
|
||||
* Get main readme path
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getMainReadmePath(): string
|
||||
{
|
||||
return $this->main_readme_path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has main readme
|
||||
*
|
||||
* @return bool
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function hasMainReadme(): bool
|
||||
{
|
||||
return !empty($this->main_readme_path);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item readme path
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getItemReadmeName(): string
|
||||
{
|
||||
return $this->item_readme_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Has item readme
|
||||
*
|
||||
* @return bool
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function hasItemReadme(): bool
|
||||
{
|
||||
return !empty($this->item_readme_name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field names of the files in the entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getFiles(): array
|
||||
{
|
||||
return $this->files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the field names of the folders in the entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getFolders(): array
|
||||
{
|
||||
return $this->folders;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get map
|
||||
*
|
||||
@@ -340,7 +433,7 @@ abstract class Config implements ConfigInterface
|
||||
* automatically removing any fields defined in $this->ignore.
|
||||
*
|
||||
* @return array Associative array in the form ['field' => 'field']
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getMap(): array
|
||||
{
|
||||
@@ -370,11 +463,22 @@ abstract class Config implements ConfigInterface
|
||||
return $this->map;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the direct entities/children of this entity
|
||||
*
|
||||
* @return array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getChildren(): array
|
||||
{
|
||||
return $this->children;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the table title name field
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getTitleName(): string
|
||||
{
|
||||
@@ -385,7 +489,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get GUID field
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getGuidField(): string
|
||||
{
|
||||
@@ -396,7 +500,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get Prefix Key
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getPrefixKey(): string
|
||||
{
|
||||
@@ -407,7 +511,7 @@ abstract class Config implements ConfigInterface
|
||||
* Get Suffix Key
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getSuffixKey(): string
|
||||
{
|
||||
|
@@ -12,9 +12,12 @@
|
||||
namespace VDM\Joomla\Abstraction\Remote;
|
||||
|
||||
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface as Config;
|
||||
use VDM\Joomla\Interfaces\GrepInterface as Grep;
|
||||
use VDM\Joomla\Interfaces\Data\ItemInterface as Item;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
use VDM\Joomla\Componentbuilder\Package\MessageBus;
|
||||
use VDM\Joomla\Interfaces\Remote\GetInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Base;
|
||||
|
||||
@@ -42,22 +45,44 @@ abstract class Get extends Base implements GetInterface
|
||||
*/
|
||||
protected Item $item;
|
||||
|
||||
/**
|
||||
* The Tracker Class.
|
||||
*
|
||||
* @var Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Tracker $tracker;
|
||||
|
||||
/**
|
||||
* The MessageBus Class.
|
||||
*
|
||||
* @var MessageBus
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected MessageBus $messages;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Config $config The Config Class.
|
||||
* @param Grep $grep The Grep Class.
|
||||
* @param Item $item The ItemInterface Class.
|
||||
* @param Tracker $tracker The Tracker Class.
|
||||
* @param MessageBus $messages The MessageBus Class.
|
||||
* @param string|null $table The table name.
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function __construct(Config $config, Grep $grep, Item $item, ?string $table = null)
|
||||
public function __construct(Config $config, Grep $grep, Item $item,
|
||||
Tracker $tracker, MessageBus $messages, ?string $table = null)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
$this->grep = $grep;
|
||||
$this->item = $item;
|
||||
$this->tracker = $tracker;
|
||||
$this->messages = $messages;
|
||||
|
||||
if ($table !== null)
|
||||
{
|
||||
$this->table($table);
|
||||
@@ -75,6 +100,7 @@ abstract class Get extends Base implements GetInterface
|
||||
*
|
||||
* @param array $items An array of item identifiers (GUIDs) to initialize and validate.
|
||||
* @param object|null $repo The repository object to search. If null, all repos will be searched.
|
||||
* @param bool $force Force a local update (if item exist locally).
|
||||
*
|
||||
* @return array{
|
||||
* local: array<string, string>,
|
||||
@@ -87,26 +113,28 @@ abstract class Get extends Base implements GetInterface
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function init(array $items, ?object $repo = null): array
|
||||
public function init(array $items, ?object $repo = null, bool $force = false): array
|
||||
{
|
||||
$done = [];
|
||||
$logger = [
|
||||
'local' => [],
|
||||
'not_found' => [],
|
||||
'added' => []
|
||||
];
|
||||
|
||||
$guid_field = $this->getGuidField();
|
||||
$table = $this->getTable();
|
||||
$this->grep->setBranchField('read_branch');
|
||||
|
||||
foreach ($items as $guid)
|
||||
{
|
||||
if (isset($done[$guid]))
|
||||
if ($this->tracker->exists("save.{$table}.{$guid_field}|{$guid}"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
$done[$guid] = $guid;
|
||||
$this->tracker->set("save.{$table}.{$guid_field}|{$guid}", true);
|
||||
|
||||
// Check if item exists in the local database
|
||||
if ($this->item->table($this->getTable())->value($guid, $guid_field) !== null)
|
||||
if ($force === false && $this->item->table($table)->value($guid, $guid_field) !== null)
|
||||
{
|
||||
$logger['local'][$guid] = $guid;
|
||||
continue;
|
||||
@@ -121,11 +149,8 @@ abstract class Get extends Base implements GetInterface
|
||||
continue;
|
||||
}
|
||||
|
||||
// pass item to the inspector to get all dependencies
|
||||
// $item = $this->model->init($item);
|
||||
|
||||
// Store the retrieved remote item into the local structure
|
||||
$this->item->set($item, $guid_field);
|
||||
$this->item->table($table)->set($item, $guid_field);
|
||||
|
||||
$logger['added'][$guid] = $guid;
|
||||
}
|
||||
@@ -143,6 +168,7 @@ abstract class Get extends Base implements GetInterface
|
||||
*/
|
||||
public function path(string $guid): ?object
|
||||
{
|
||||
$this->grep->setBranchField('read_branch');
|
||||
return $this->grep->getPath($guid);
|
||||
}
|
||||
|
||||
@@ -154,6 +180,7 @@ abstract class Get extends Base implements GetInterface
|
||||
*/
|
||||
public function paths(): ?array
|
||||
{
|
||||
$this->grep->setBranchField('read_branch');
|
||||
return $this->grep->getPaths();
|
||||
}
|
||||
|
||||
@@ -168,7 +195,9 @@ abstract class Get extends Base implements GetInterface
|
||||
public function list(?string $repo = null): ?array
|
||||
{
|
||||
$guid_field = $this->getGuidField();
|
||||
$table = $this->item->table($this->getTable());
|
||||
$entity = $this->getTable();
|
||||
$table = $this->item->table($entity);
|
||||
$this->grep->setBranchField('read_branch');
|
||||
|
||||
if ($repo === null)
|
||||
{
|
||||
@@ -185,16 +214,34 @@ abstract class Get extends Base implements GetInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
foreach ($paths as &$path)
|
||||
$list = [];
|
||||
foreach ($paths as $path)
|
||||
{
|
||||
foreach ($path->index as &$item)
|
||||
if (!is_object($path->index[$entity] ?? null))
|
||||
{
|
||||
$guid = $item->{$guid_field};
|
||||
continue;
|
||||
}
|
||||
|
||||
$repo = clone $path;
|
||||
$repo->index = $path->index[$entity];
|
||||
|
||||
foreach ($repo->index as $key => $item)
|
||||
{
|
||||
$guid = $item->guid ?? $item->{$guid_field} ?? null;
|
||||
if (!isset($guid))
|
||||
{
|
||||
unset($repo->index->{$key});
|
||||
continue;
|
||||
}
|
||||
$item->local = $table->value($guid, $guid_field) !== null;
|
||||
}
|
||||
|
||||
$this->normalizeObjectIndexHeader($repo->index);
|
||||
|
||||
$list[] = $repo;
|
||||
}
|
||||
|
||||
return $paths;
|
||||
return $list ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -213,15 +260,22 @@ abstract class Get extends Base implements GetInterface
|
||||
}
|
||||
|
||||
$success = true;
|
||||
$area = $this->getArea();
|
||||
|
||||
foreach($items as $guid)
|
||||
{
|
||||
if (!$this->item($guid, ['remote']))
|
||||
{
|
||||
$success = false;
|
||||
$this->messages->add('warning', Text::sprintf('COM_COMPONENTBUILDER_THE_S_ITEMS_DID_NOT_RESET', strtolower($area), $guid));
|
||||
}
|
||||
}
|
||||
|
||||
if ($success)
|
||||
{
|
||||
$this->messages->add('success', Text::sprintf('COM_COMPONENTBUILDER_THE_S_ITEMS_WAS_RESET', strtolower($area)));
|
||||
}
|
||||
|
||||
return $success;
|
||||
}
|
||||
|
||||
@@ -239,14 +293,64 @@ abstract class Get extends Base implements GetInterface
|
||||
public function item(string $guid, array $order = ['remote', 'local'], ?object $repo = null): bool
|
||||
{
|
||||
$guid_field = $this->getGuidField();
|
||||
$table = $this->getTable();
|
||||
$this->grep->setBranchField('read_branch');
|
||||
$result = false;
|
||||
|
||||
if ($this->tracker->exists("save.{$table}.{$guid_field}|{$guid}"))
|
||||
{
|
||||
return $this->tracker->get("save.{$table}.{$guid_field}|{$guid}");
|
||||
}
|
||||
|
||||
if (($item = $this->grep->get($guid, $order, $repo)) !== null)
|
||||
{
|
||||
// pass item to the model to set the direct children
|
||||
// $item = $this->model->getItem($item);
|
||||
return $this->item->table($this->getTable())->set($item, $guid_field);
|
||||
$result = $this->item->table($table)->set($item, $guid_field);
|
||||
}
|
||||
|
||||
return false;
|
||||
$this->tracker->set("save.{$table}.{$guid_field}|{$guid}", $result);
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Normalize an object of objects (indexed by GUID):
|
||||
* - Each sub-object is normalized to have all keys in the order from getIndexHeader().
|
||||
* - Missing keys are filled with an empty string.
|
||||
* - The outer GUID keys are preserved.
|
||||
*
|
||||
* @param object &$items Object of stdClass sub-objects, passed by reference
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function normalizeObjectIndexHeader(object &$items): void
|
||||
{
|
||||
$canonicalKeys = $this->getIndexHeader();
|
||||
|
||||
$expectedCount = count($canonicalKeys);
|
||||
$template = array_fill_keys($canonicalKeys, '');
|
||||
|
||||
foreach ($items as $guid => &$subObject)
|
||||
{
|
||||
if (!is_object($subObject))
|
||||
{
|
||||
continue; // skip if not an object
|
||||
}
|
||||
|
||||
$vars = get_object_vars($subObject);
|
||||
|
||||
// Skip normalization if already compliant
|
||||
if (count($vars) === $expectedCount && array_keys($vars) === $canonicalKeys)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Normalize: enforce key order and fill missing values
|
||||
$subObject = (object) array_merge($template, $vars);
|
||||
}
|
||||
|
||||
unset($subObject); // break reference
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -19,7 +19,9 @@ use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
|
||||
use VDM\Joomla\Interfaces\Readme\ItemInterface as ItemReadme;
|
||||
use VDM\Joomla\Interfaces\Readme\MainInterface as MainReadme;
|
||||
use VDM\Joomla\Interfaces\Git\Repository\ContentsInterface as Git;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
use VDM\Joomla\Componentbuilder\Package\MessageBus;
|
||||
use VDM\Joomla\Interfaces\Remote\Dependency\ResolverInterface as Resolver;
|
||||
use VDM\Joomla\Utilities\ObjectHelper;
|
||||
use VDM\Joomla\Interfaces\Remote\SetInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Base;
|
||||
@@ -72,14 +74,33 @@ abstract class Set extends Base implements SetInterface
|
||||
*/
|
||||
protected Git $git;
|
||||
|
||||
/**
|
||||
* The Tracker Class.
|
||||
*
|
||||
* @var Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Tracker $tracker;
|
||||
|
||||
/**
|
||||
* The Message Bus Class.
|
||||
*
|
||||
* @var MessageBus
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected MessageBus $messages;
|
||||
|
||||
/**
|
||||
* The Resolver Class
|
||||
*
|
||||
* Only set in some child classes
|
||||
* that has dependencies
|
||||
*
|
||||
* @var Resolver
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ?Resolver $resolver = null;
|
||||
|
||||
/**
|
||||
* All active repos
|
||||
*
|
||||
@@ -94,7 +115,7 @@ abstract class Set extends Base implements SetInterface
|
||||
* @var array
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected array $settings;
|
||||
protected array $settings = [];
|
||||
|
||||
/**
|
||||
* Repo Placeholders
|
||||
@@ -113,17 +134,18 @@ abstract class Set extends Base implements SetInterface
|
||||
* @param ItemReadme $itemReadme The Item Readme Class.
|
||||
* @param MainReadme $mainReadme The Main Readme Class.
|
||||
* @param Git $git The Contents Class.
|
||||
* @param Tracker $tracker The Tracker Class.
|
||||
* @param MessageBus $messages The MessageBus Class.
|
||||
* @param array $repos The active repos.
|
||||
* @param string|null $table The table name.
|
||||
* @param string|null $settingsPath The settings path.
|
||||
* @param string|null $settingsName The settings name.
|
||||
* @param string|null $indexPath The index path.
|
||||
*
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function __construct(Config $config, Grep $grep, Items $items, ItemReadme $itemReadme,
|
||||
MainReadme $mainReadme, Git $git, MessageBus $messages, array $repos, ?string $table = null,
|
||||
?string $settingsPath = null, ?string $indexPath = null)
|
||||
MainReadme $mainReadme, Git $git, Tracker $tracker, MessageBus $messages,
|
||||
array $repos, ?string $table = null, ?string $settingsName = null, ?string $indexPath = null)
|
||||
{
|
||||
parent::__construct($config);
|
||||
|
||||
@@ -132,6 +154,7 @@ abstract class Set extends Base implements SetInterface
|
||||
$this->itemReadme = $itemReadme;
|
||||
$this->mainReadme = $mainReadme;
|
||||
$this->git = $git;
|
||||
$this->tracker = $tracker;
|
||||
$this->messages = $messages;
|
||||
$this->repos = $repos;
|
||||
|
||||
@@ -140,9 +163,9 @@ abstract class Set extends Base implements SetInterface
|
||||
$this->table($table);
|
||||
}
|
||||
|
||||
if ($settingsPath !== null)
|
||||
if ($settingsName !== null)
|
||||
{
|
||||
$this->setSettingsPath($settingsPath);
|
||||
$this->setSettingsName($settingsName);
|
||||
}
|
||||
|
||||
if ($indexPath !== null)
|
||||
@@ -155,7 +178,6 @@ abstract class Set extends Base implements SetInterface
|
||||
$this->area(ucfirst(str_replace('_', ' ', $this->getTable())));
|
||||
}
|
||||
|
||||
// set the branch to writing
|
||||
$this->grep->setBranchField('write_branch');
|
||||
}
|
||||
|
||||
@@ -165,22 +187,30 @@ abstract class Set extends Base implements SetInterface
|
||||
* @param array $guids The global unique id of the item
|
||||
*
|
||||
* @return bool
|
||||
* @throws \Exception
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function items(array $guids): bool
|
||||
{
|
||||
if (!$this->canWrite())
|
||||
if (empty($guids))
|
||||
{
|
||||
throw new \Exception("At least one [{$this->getArea()}] content repository must be configured with a [Write Branch] value in the repositories area for the push function to operate correctly.");
|
||||
return false;
|
||||
}
|
||||
|
||||
// we reset the index settings
|
||||
$this->settings = [];
|
||||
$this->grep->setBranchField('write_branch');
|
||||
$area = $this->getArea();
|
||||
$table = $this->getTable();
|
||||
|
||||
if (!$this->canWrite())
|
||||
{
|
||||
$target_network = $this->grep->getNetworkTarget() ?? $this->getArea();
|
||||
$this->messages->add('error', Text::sprintf('COM_COMPONENTBUILDER_AT_LEAST_ONE_S_CONTENT_REPOSITORY_MUST_BE_CONFIGURED_WITH_A_WRITE_BRANCH_VALUE_IN_THE_REPOSITORIES_AREA_FOR_THE_PUSH_FUNCTION_TO_OPERATE_CORRECTLY', $target_network));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($items = $this->getLocalItems($guids)) === null)
|
||||
{
|
||||
throw new \Exception("At least one valid local [{$this->getArea()}] must exist for the push function to operate correctly.");
|
||||
$this->messages->add('warning', Text::sprintf('COM_COMPONENTBUILDER_THE_S_ITEMS_COULD_NOT_BE_FOUND', strtolower($area)));
|
||||
return false;
|
||||
}
|
||||
|
||||
$counter = 0;
|
||||
@@ -201,6 +231,14 @@ abstract class Set extends Base implements SetInterface
|
||||
}
|
||||
}
|
||||
|
||||
// add a message per area once
|
||||
if ($counter > 0 && !$this->tracker->exists("message.{$table}"))
|
||||
{
|
||||
$this->tracker->set("message.{$table}", true);
|
||||
$item_name = $counter == 1 ? 'item has' : 'items have';
|
||||
$this->messages->add('success', Text::sprintf('COM_COMPONENTBUILDER_S_S_BEEN_PUSHED_SUCCESSFULLY', $area, $item_name));
|
||||
}
|
||||
|
||||
return $counter === count($items);
|
||||
}
|
||||
|
||||
@@ -276,31 +314,42 @@ abstract class Set extends Base implements SetInterface
|
||||
|
||||
$settings = $this->mergeIndexSettings($repoGuid, $settings);
|
||||
|
||||
$this->grep->loadApi($this->git, $repo->base ?? null, $repo->token ?? null);
|
||||
// set the target system
|
||||
$target = $repo->target ?? 'gitea';
|
||||
$this->git->setTarget($target);
|
||||
|
||||
$indexPath = $this->getIndexPath();
|
||||
if (!empty($indexPath))
|
||||
{
|
||||
$this->setMainRepoFile(
|
||||
$repo,
|
||||
$indexPath,
|
||||
json_encode($settings, JSON_PRETTY_PRINT),
|
||||
'Update main index file', 'Create main index file'
|
||||
);
|
||||
// load the base and token if set
|
||||
$this->grep->loadApi(
|
||||
$this->git,
|
||||
$target === 'gitea' ? ($repo->base ?? null) : null,
|
||||
$repo->token ?? null
|
||||
);
|
||||
|
||||
try {
|
||||
$indexPath = $this->getIndexPath();
|
||||
if (!empty($indexPath))
|
||||
{
|
||||
$this->setMainRepoFile(
|
||||
$repo,
|
||||
$indexPath,
|
||||
json_encode($settings, JSON_PRETTY_PRINT),
|
||||
'Update main index file', 'Create main index file'
|
||||
);
|
||||
}
|
||||
if ($this->hasMainReadme())
|
||||
{
|
||||
$this->setMainRepoFile(
|
||||
$repo,
|
||||
$this->getMainReadmePath(),
|
||||
$this->mainReadme->get($settings),
|
||||
'Update main readme file', 'Create main readme file'
|
||||
);
|
||||
}
|
||||
} catch (\Throwable $e) {
|
||||
$this->messages->add('error', $e->getMessage());
|
||||
} finally {
|
||||
$this->git->reset_();
|
||||
}
|
||||
|
||||
$mainReadmePath = $this->getMainReadmePath();
|
||||
if (!empty($mainReadmePath))
|
||||
{
|
||||
$this->setMainRepoFile(
|
||||
$repo,
|
||||
$mainReadmePath,
|
||||
$this->mainReadme->get($settings),
|
||||
'Update main readme file', 'Create main readme file'
|
||||
);
|
||||
}
|
||||
|
||||
$this->git->reset_();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -364,12 +413,16 @@ abstract class Set extends Base implements SetInterface
|
||||
protected function setMainRepoFile(object $repo, string $path,
|
||||
string $content, string $updateMessage, string $createMessage): void
|
||||
{
|
||||
$meta = $this->git->metadata(
|
||||
$repo->organisation,
|
||||
$repo->repository,
|
||||
$path,
|
||||
$repo->write_branch
|
||||
);
|
||||
try {
|
||||
$meta = $this->git->metadata(
|
||||
$repo->organisation,
|
||||
$repo->repository,
|
||||
$path,
|
||||
$repo->write_branch
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$meta = null;
|
||||
}
|
||||
|
||||
if ($meta !== null && isset($meta->sha))
|
||||
{
|
||||
@@ -382,26 +435,38 @@ abstract class Set extends Base implements SetInterface
|
||||
return;
|
||||
}
|
||||
|
||||
$this->git->update(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$path, // The file path.
|
||||
$content, // The file content.
|
||||
$updateMessage, // The commit message.
|
||||
$meta->sha, // The previous sha value.
|
||||
$repo->write_branch // The branch name.
|
||||
);
|
||||
try {
|
||||
$this->git->update(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$path, // The file path.
|
||||
$content, // The file content.
|
||||
$updateMessage, // The commit message.
|
||||
$meta->sha, // The previous sha value.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author name.
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->messages->add('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->git->create(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$path, // The file path.
|
||||
$content, // The file content.
|
||||
$createMessage, // The commit message.
|
||||
$repo->write_branch // The branch name.
|
||||
);
|
||||
try {
|
||||
$this->git->create(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$path, // The file path.
|
||||
$content, // The file content.
|
||||
$createMessage, // The commit message.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author name.
|
||||
);
|
||||
} catch (\Throwable $e) {
|
||||
$this->messages->add('error', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,9 +506,24 @@ abstract class Set extends Base implements SetInterface
|
||||
$this->messages->add('error', Text::sprintf('COM_COMPONENTBUILDER_S_ITEM_S_ID_S_MISSING_THE_S_KEY_VALUE', $area, $item_name, $item_id, $guid_field));
|
||||
return false;
|
||||
}
|
||||
$table = $this->getTable();
|
||||
$guid = $item->{$guid_field};
|
||||
|
||||
// pass item to the inspector to set all dependencies
|
||||
// $item = $this->model->setItem($item);
|
||||
// check if we have saved this entity already
|
||||
if ($this->tracker->exists("save.{$table}.{$guid_field}|{$guid}"))
|
||||
{
|
||||
return $this->tracker->get("save.{$table}.{$guid_field}|{$guid}");
|
||||
}
|
||||
|
||||
// pass item to the inspector/resolver to get all dependencies
|
||||
$dependencies = $this->getDependencies($item);
|
||||
if ($dependencies !== null)
|
||||
{
|
||||
foreach ($dependencies as $key => $dependency)
|
||||
{
|
||||
$item->{$key} = $dependency;
|
||||
}
|
||||
}
|
||||
|
||||
$at_least_once = false;
|
||||
$not_approved = true;
|
||||
@@ -457,40 +537,59 @@ abstract class Set extends Base implements SetInterface
|
||||
|
||||
$this->setRepoPlaceholders($repo);
|
||||
|
||||
$this->grep->loadApi($this->git, $repo->base ?? null, $repo->token ?? null);
|
||||
// set the target system
|
||||
$target_system = $repo->target ?? 'gitea';
|
||||
$this->git->setTarget($target_system);
|
||||
|
||||
if (($existing = $this->grep->get($item->{$guid_field}, ['remote'], $repo)) !== null)
|
||||
{
|
||||
if ($this->updateItem($item, $existing, $repo))
|
||||
// load the base and token if set
|
||||
$this->grep->loadApi(
|
||||
$this->git,
|
||||
$target_system === 'gitea' ? ($repo->base ?? null) : null,
|
||||
$repo->token ?? null
|
||||
);
|
||||
|
||||
try {
|
||||
if (($existing = $this->grep->get($guid, ['remote'], $repo)) !== null)
|
||||
{
|
||||
$this->updateItemReadme($item, $existing, $repo);
|
||||
$at_least_once = true;
|
||||
if ($this->updateItem($item, $existing, $repo))
|
||||
{
|
||||
$this->updateItemReadme($item, $existing, $repo);
|
||||
$at_least_once = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
elseif ($this->createItem($item, $repo))
|
||||
{
|
||||
$this->createItemReadme($item, $repo);
|
||||
|
||||
$index_item ??= $this->getIndexItem($item);
|
||||
|
||||
$at_least_once = true;
|
||||
|
||||
if (!isset($this->settings[$key]))
|
||||
elseif ($this->createItem($item, $repo))
|
||||
{
|
||||
$this->settings[$key] = ['repo' => $repo, 'items' => [$item->{$guid_field} => $index_item]];
|
||||
$this->createItemReadme($item, $repo);
|
||||
|
||||
$index_item ??= $this->getIndexItem($item);
|
||||
|
||||
$at_least_once = true;
|
||||
|
||||
if (!isset($this->settings[$key]))
|
||||
{
|
||||
$this->settings[$key] = ['repo' => $repo, 'items' => [$guid => $index_item]];
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->settings[$key]['items'][$guid] = $index_item;
|
||||
$this->settings[$key]['repo'] = $repo;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->settings[$key]['items'][$item->{$guid_field}] = $index_item;
|
||||
$repo_name = $this->getRepoName($repo);
|
||||
$this->messages->add('error',
|
||||
Text::sprintf('COM_COMPONENTBUILDER_S_ITEM_S_ID_S_COULD_NOT_BE_CREATED_OR_FOUND_IN_REPOS',
|
||||
$area, $item_name, $item_id, $repo_name));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} catch (\Throwable $e) {
|
||||
$repo_name = $this->getRepoName($repo);
|
||||
$this->messages->add('error', Text::sprintf('COM_COMPONENTBUILDER_S_ITEM_S_ID_S_COULD_NOT_BE_CREATED_OR_FOUND_IN_REPOS', $area, $item_name, $item_id, $repo_name));
|
||||
$this->messages->add('error',
|
||||
Text::sprintf('COM_COMPONENTBUILDER_S_ITEM_S_ID_S_ENCOUNTERED_AN_ERROR_IN_REPOSBRERROR_MESSAGEBRS',
|
||||
$area, $item_name, $item_id, $repo_name, $e->getMessage()));
|
||||
} finally {
|
||||
$this->git->reset_();
|
||||
}
|
||||
|
||||
$this->git->reset_();
|
||||
}
|
||||
|
||||
if (!$at_least_once && $not_approved)
|
||||
@@ -498,6 +597,8 @@ abstract class Set extends Base implements SetInterface
|
||||
$this->messages->add('warning', Text::sprintf('COM_COMPONENTBUILDER_S_ITEM_S_ID_S_IS_NOT_APPROVED_AND_THEREFORE_NOT_LINKED_TO_ANY_REPOSITORY', $area, $item_name, $item_id));
|
||||
}
|
||||
|
||||
$this->tracker->set("save.{$table}.{$guid_field}|{$guid}", $at_least_once);
|
||||
|
||||
return $at_least_once;
|
||||
}
|
||||
|
||||
@@ -521,6 +622,23 @@ abstract class Set extends Base implements SetInterface
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the dependencies of this item
|
||||
*
|
||||
* @param object $item The item to resolve the dependencies
|
||||
*
|
||||
* @return array|null The array of relationships or null for none
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected function getDependencies($item): ?array
|
||||
{
|
||||
if ($this->resolver instanceof Resolver)
|
||||
{
|
||||
return $this->resolver->extract($item);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update Placeholders in String
|
||||
*
|
||||
@@ -577,7 +695,7 @@ abstract class Set extends Base implements SetInterface
|
||||
* @param object $repo The current repo
|
||||
*
|
||||
* @return string
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getRepoName(object $repo): string
|
||||
{
|
||||
@@ -604,7 +722,7 @@ abstract class Set extends Base implements SetInterface
|
||||
*/
|
||||
protected function areObjectsEqual(?object $obj1, ?object $obj2): bool
|
||||
{
|
||||
return ObjectHelper::equal($obj1, $obj2); // basic comparison
|
||||
return ObjectHelper::equal($obj1, $obj2, ['@dependencies']); // basic comparison
|
||||
}
|
||||
}
|
||||
|
||||
|
370
libraries/vendor_jcb/VDM.Joomla/src/Abstraction/Versioning.php
Normal file
370
libraries/vendor_jcb/VDM.Joomla/src/Abstraction/Versioning.php
Normal file
@@ -0,0 +1,370 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Abstraction;
|
||||
|
||||
|
||||
use Joomla\CMS\Application\CMSApplicationInterface as CMSApplication;
|
||||
use Joomla\CMS\Component\ComponentHelper;
|
||||
use Joomla\CMS\Date\Date;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Table\ContentHistory;
|
||||
use Joomla\CMS\Table\ContentType;
|
||||
use Joomla\CMS\Table\TableInterface;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\Database\DatabaseInterface as JoomlaDatabase;
|
||||
use Joomla\Registry\Registry;
|
||||
use VDM\Joomla\Utilities\Component\Helper;
|
||||
use VDM\Joomla\Interfaces\Database\VersioningInterface;
|
||||
use VDM\Joomla\Abstraction\Database;
|
||||
|
||||
|
||||
/**
|
||||
* Versioning
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
abstract class Versioning extends Database implements VersioningInterface
|
||||
{
|
||||
/**
|
||||
* CMS Application
|
||||
*
|
||||
* @var CMSApplication
|
||||
* @since 5.1.1
|
||||
**/
|
||||
protected CMSApplication $app;
|
||||
|
||||
/**
|
||||
* Joomla History Class
|
||||
*
|
||||
* @var ContentHistory
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ContentHistory $contentHistory;
|
||||
|
||||
/**
|
||||
* Joomla Content Type Class
|
||||
*
|
||||
* @var ContentType
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ContentType $typeTable;
|
||||
|
||||
/**
|
||||
* Current component params
|
||||
*
|
||||
* @var Registry
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Registry $params;
|
||||
|
||||
/**
|
||||
* Current user ID
|
||||
*
|
||||
* @var int
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected int $userId;
|
||||
|
||||
/**
|
||||
* Current component code name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $componentNamespace;
|
||||
|
||||
/**
|
||||
* The current entity
|
||||
*
|
||||
* @var string|null
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ?string $entity;
|
||||
|
||||
/**
|
||||
* Switch to set the history
|
||||
*
|
||||
* @var int
|
||||
* @since 5.1.1
|
||||
**/
|
||||
protected int $history;
|
||||
|
||||
/**
|
||||
* Number of max item versions to store in history
|
||||
*
|
||||
* @var int
|
||||
* @since 5.1.1
|
||||
**/
|
||||
protected int $maxVersions;
|
||||
|
||||
/**
|
||||
* Class constructor.
|
||||
*
|
||||
* Initializes the component context by setting the application, database,
|
||||
* content history tracking, and content type table instances. Also loads
|
||||
* component-specific parameters like history tracking and version limits.
|
||||
*
|
||||
* @param JoomlaDatabase|null $db Optional database object. Defaults to Joomla's factory DB.
|
||||
* @param CMSApplication|null $app Optional application object. Defaults to Factory::getApplication().
|
||||
* @param ContentHistory|null $history Optional content history table instance. Defaults to new ContentHistory.
|
||||
* @param ContentType|null $typeTable Optional content type table instance. Defaults to new ContentType.
|
||||
*
|
||||
* @throws \Exception If the parent constructor or any dependency throws.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(?JoomlaDatabase $db = null, ?CMSApplication $app = null,
|
||||
?ContentHistory $history = null, ?ContentType $typeTable = null)
|
||||
{
|
||||
parent::__construct($db);
|
||||
|
||||
$this->app = $app ?: Factory::getApplication();
|
||||
$this->contentHistory = $history ?: new ContentHistory($this->db);
|
||||
$this->typeTable = $typeTable ?: new ContentType($this->db);
|
||||
|
||||
$user = $this->app->getIdentity();
|
||||
$this->userId = $user instanceof User ? (int) $user->id : 0;
|
||||
|
||||
// set the component details
|
||||
$this->componentNamespace = Helper::getNamespace();
|
||||
$this->params = Helper::getParams();
|
||||
$this->history = $this->params->get('save_history', 0);
|
||||
$this->maxVersions = $this->params->get('history_limit', 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Switch to prevent/allow history from being set.
|
||||
*
|
||||
* @param int|null $trigger toggle the history (0 = no, 1 = yes, null = default)
|
||||
*
|
||||
* @return self
|
||||
* @since 5.1.1
|
||||
**/
|
||||
public function history(?int $trigger = null): self
|
||||
{
|
||||
$this->history = $trigger !== null ? $trigger : $this->params->get('save_history', 0);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save a history record for a stored item.
|
||||
*
|
||||
* @param int $id The ID of the record
|
||||
*
|
||||
* @return bool True if saved, false if skipped or failed
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function setHistory(int $id): bool
|
||||
{
|
||||
$tableClass = $this->getTableClass();
|
||||
|
||||
if ($tableClass === null)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @var TableInterface $table */
|
||||
$table = new $tableClass($this->db);
|
||||
|
||||
if (!$table->load($id))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// set the type alias
|
||||
$type_alias = 'com_' . $this->componentCode . '.' . $this->entity;
|
||||
|
||||
$item = (object) $table->getProperties();
|
||||
unset($item->typeAlias, $item->tagsHelper);
|
||||
|
||||
// Required: item_id, version_data, editor_user_id
|
||||
$this->contentHistory->reset();
|
||||
$this->contentHistory->version_id = null;
|
||||
$this->contentHistory->item_id = $type_alias . '.' . $id;
|
||||
$this->contentHistory->version_note = '';
|
||||
$this->contentHistory->version_data = json_encode($item);
|
||||
$this->contentHistory->editor_user_id = $this->userId;
|
||||
$this->contentHistory->save_date = (new Date())->toSql();
|
||||
|
||||
// Don't save if hash already exists and same version note
|
||||
$this->typeTable->load(['type_alias' => $type_alias]);
|
||||
$this->contentHistory->sha1_hash = $this->contentHistory->getSha1($item, $this->typeTable);
|
||||
|
||||
if ($this->contentHistory->getHashMatch())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
$result = $this->contentHistory->store();
|
||||
|
||||
$max_versions_context = $this->params->get('history_limit_' . $this->entity, 0);
|
||||
|
||||
if ($max_versions_context)
|
||||
{
|
||||
$this->contentHistory->deleteOldVersions($max_versions_context);
|
||||
}
|
||||
elseif ($this->maxVersions)
|
||||
{
|
||||
$this->contentHistory->deleteOldVersions($this->maxVersions);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save multiple version records for already stored items.
|
||||
*
|
||||
* @param int[] $ids Array of IDs
|
||||
* @param string $entity Table entity name
|
||||
*
|
||||
* @return int Number of successful version saves
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function setMultipleHistory(array $ids): int
|
||||
{
|
||||
$tableClass = $this->getTableClass();
|
||||
|
||||
if ($tableClass === null)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** @var TableInterface $table */
|
||||
$table = new $tableClass($this->db);
|
||||
|
||||
// set some var needed in loop
|
||||
$date = (new Date())->toSql();
|
||||
$max_versions_context = $this->params->get('history_limit_' . $this->entity, 0);
|
||||
$type_alias = 'com_' . $this->componentCode . '.' . $this->entity;
|
||||
$this->typeTable->load(['type_alias' => $type_alias]);
|
||||
$count = 0;
|
||||
|
||||
foreach ($ids as $id)
|
||||
{
|
||||
$id = (int) $id;
|
||||
if ($id <= 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!$table->load($id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$item = (object) $table->getProperties();
|
||||
unset($item->typeAlias, $item->tagsHelper);
|
||||
|
||||
$this->contentHistory->reset();
|
||||
$this->contentHistory->version_id = null;
|
||||
$this->contentHistory->item_id = $type_alias . '.' . $id;
|
||||
$this->contentHistory->version_note = '';
|
||||
$this->contentHistory->version_data = json_encode($item);
|
||||
$this->contentHistory->editor_user_id = $this->userId;
|
||||
$this->contentHistory->save_date = $date;
|
||||
|
||||
// Don't save if hash already exists and same version note
|
||||
$this->contentHistory->sha1_hash = $this->contentHistory->getSha1($item, $this->typeTable);
|
||||
|
||||
if ($this->contentHistory->getHashMatch())
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$result = $this->contentHistory->store();
|
||||
|
||||
if ($max_versions_context)
|
||||
{
|
||||
$this->contentHistory->deleteOldVersions($max_versions_context);
|
||||
}
|
||||
elseif ($this->maxVersions)
|
||||
{
|
||||
$this->contentHistory->deleteOldVersions($this->maxVersions);
|
||||
}
|
||||
|
||||
if ($result)
|
||||
{
|
||||
++$count;
|
||||
}
|
||||
}
|
||||
|
||||
return $count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the fully qualified class name for a table if it exists.
|
||||
*
|
||||
* This method first extracts the base table name using `getTableName`.
|
||||
* If the extraction fails (e.g., wrong component prefix), it returns null.
|
||||
* If successful, it constructs the FQCN in the format:
|
||||
* \Namespace\Component\ComponentName\Administrator\Table\TableNameTable
|
||||
*
|
||||
* The table name is converted to PascalCase and suffixed with `Table`.
|
||||
* The constructed class name is verified with `class_exists`.
|
||||
*
|
||||
* @return string|null The fully qualified class name, or null if it does not exist.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getTableClass(): ?string
|
||||
{
|
||||
if (empty($this->entity))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$tableClass = ucfirst($this->entity) . 'Table';
|
||||
|
||||
$class = $this->componentNamespace . '\\Administrator\\Table\\' . $tableClass;
|
||||
if (!class_exists($class))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return $class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the actual table name by removing the component prefix.
|
||||
*
|
||||
* This method checks whether the given table name includes the component-specific prefix,
|
||||
* which usually starts with `#__` followed by the component name and an underscore (e.g., `#__mycomponent_`).
|
||||
* If it matches this instance's component prefix stored in `$this->table`, the prefix is stripped and the short table name is returned.
|
||||
* If the prefix is different (implying a foreign component), `null` is returned.
|
||||
* If no prefix is present, the original value is returned unchanged.
|
||||
*
|
||||
* @param string $table The full or short table name.
|
||||
*
|
||||
* @return string|null The stripped table name, original if no prefix is found, or null if not removable.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getTableEntityName(string $table): ?string
|
||||
{
|
||||
if (strpos($table, '#__') === false)
|
||||
{
|
||||
return $table;
|
||||
}
|
||||
|
||||
if (empty($this->table))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
$prefix = $this->table . '_';
|
||||
if (str_starts_with($table, $prefix))
|
||||
{
|
||||
return substr($table, strlen($prefix));
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Architecture\JoomlaFive\Plugin;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Set;
|
||||
@@ -542,7 +542,7 @@ final class MainXML implements MainXMLInterface
|
||||
|
||||
$path = "{$plugin->folder_path}/language/{$tag}/";
|
||||
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
$this->counter->folder++;
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Architecture\JoomlaFour\Plugin;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Set;
|
||||
@@ -542,7 +542,7 @@ final class MainXML implements MainXMLInterface
|
||||
|
||||
$path = "{$plugin->folder_path}/language/{$tag}/";
|
||||
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
$this->counter->folder++;
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Architecture\JoomlaThree\Plugin;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Language\Set;
|
||||
@@ -543,7 +543,7 @@ final class MainXML implements MainXMLInterface
|
||||
|
||||
$path = "{$plugin->folder_path}/language/{$tag}/";
|
||||
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
$this->counter->folder++;
|
||||
|
@@ -1021,7 +1021,7 @@ final class Data
|
||||
if (StringHelper::check($component->bom))
|
||||
{
|
||||
$this->config->set('bom_path',
|
||||
$this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/' . $component->bom
|
||||
$this->config->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler') . '/' . $component->bom
|
||||
);
|
||||
}
|
||||
unset($component->bom);
|
||||
|
@@ -15,8 +15,8 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Component;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\Filesystem\File;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Registry;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
@@ -410,7 +410,7 @@ final class Structuresingle
|
||||
|
||||
return false;
|
||||
}
|
||||
elseif ($details->type === 'folder' && !Folder::exists($this->currentFullPath))
|
||||
elseif ($details->type === 'folder' && !is_dir($this->currentFullPath))
|
||||
{
|
||||
$this->app->enqueueMessage(
|
||||
Text::_('COM_COMPONENTBUILDER_HR_HTHREEFOLDER_PATH_ERRORHTHREE'),
|
||||
@@ -474,7 +474,7 @@ final class Structuresingle
|
||||
);
|
||||
|
||||
// check if path exist, if not creat it
|
||||
if (!Folder::exists($packageFullPath0nly))
|
||||
if (!is_dir($packageFullPath0nly))
|
||||
{
|
||||
Folder::create($packageFullPath0nly);
|
||||
}
|
||||
|
@@ -735,7 +735,7 @@ class Config extends ComponentConfig
|
||||
// get the compiler path
|
||||
return $this->params->get(
|
||||
'compiler_folder_path',
|
||||
JPATH_COMPONENT_ADMINISTRATOR . '/compiler'
|
||||
JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler'
|
||||
);
|
||||
}
|
||||
|
||||
@@ -947,7 +947,7 @@ class Config extends ComponentConfig
|
||||
// get the custom folder path
|
||||
return $this->params->get(
|
||||
'custom_folder_path',
|
||||
JPATH_COMPONENT_ADMINISTRATOR . '/custom'
|
||||
JPATH_ADMINISTRATOR . '/components/com_componentbuilder/custom'
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -61,7 +61,7 @@ final class FieldDynamic implements Fielddynamicinterface
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
|
@@ -100,7 +100,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
@@ -124,7 +124,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
* The ComponentFields Class.
|
||||
*
|
||||
* @var ComponentFields
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ComponentFields $componentfields;
|
||||
|
||||
@@ -1065,7 +1065,7 @@ final class FieldString implements Fieldtypeinterface
|
||||
* @param array $link The link data which may contain 'table', 'component', 'view', 'text', and 'id'.
|
||||
*
|
||||
* @return array|null The structured linker relation array, or null if input is an empty array.
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function setLinkerRelations(array $link): ?array
|
||||
{
|
||||
|
@@ -99,7 +99,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* The ModalSelect Class.
|
||||
*
|
||||
* @var ModalSelect
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ModalSelect $modalselect;
|
||||
|
||||
@@ -131,7 +131,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* The ComponentFields Class.
|
||||
*
|
||||
* @var ComponentFields
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ComponentFields $componentfields;
|
||||
|
||||
@@ -234,7 +234,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray The option bucket array used to set the field options if needed.
|
||||
*
|
||||
* @return \stdClass The field in xml object
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildOptionField(array &$fieldAttributes, string $name, string $typeName,
|
||||
string $langView, string $nameSingleCode, string $nameListCode,
|
||||
@@ -296,7 +296,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param string $typeName The field type
|
||||
*
|
||||
* @return \stdClass The field in xml object
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildPlainField(array &$fieldAttributes, string $name, string $typeName): \stdClass
|
||||
{
|
||||
@@ -318,7 +318,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param string $typeName The field type
|
||||
*
|
||||
* @return \stdClass The field in xml object
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildSpacerField(array &$fieldAttributes, string $name, string $typeName): \stdClass
|
||||
{
|
||||
@@ -345,7 +345,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $placeholders
|
||||
*
|
||||
* @return \stdClass
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildSpecialField(array &$fieldAttributes, string $name, array &$subform, string $typeName,
|
||||
string $langView, string $nameSingleCode, string $nameListCode,
|
||||
@@ -379,7 +379,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $custom
|
||||
*
|
||||
* @return \stdClass
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildCustomField(array &$fieldAttributes, string &$name, string &$typeName,
|
||||
string &$langView, string &$nameSingleCode, string &$nameListCode,
|
||||
@@ -454,7 +454,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $placeholders
|
||||
*
|
||||
* @return \stdClass
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildSubformField(array &$fieldAttributes, string $name, array &$subform, string $typeName,
|
||||
string $langView, string $nameSingleCode, string $nameListCode,
|
||||
@@ -624,7 +624,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $custom Used when field is from config
|
||||
*
|
||||
* @return \stdClass The field in xml object
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function getSubformField(string $setType, array &$fieldAttributes, string $name, array &$subform,
|
||||
string $typeName, string $langView, string $nameSingleCode, string $nameListCode,
|
||||
@@ -669,7 +669,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $placeholders
|
||||
*
|
||||
* @return \stdClass
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildRepeatableField(array &$fieldAttributes, string $name, string $typeName,
|
||||
string $langView, string $nameSingleCode, string $nameListCode,
|
||||
@@ -833,7 +833,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildSingleOption(\SimpleXMLElement $fieldXML, string $value, string $langView, ?array &$optionArray): void
|
||||
{
|
||||
@@ -867,7 +867,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildMultipleOptions(\SimpleXMLElement $fieldXML, string $value, string $langView, ?array &$optionArray): void
|
||||
{
|
||||
@@ -889,7 +889,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function buildGroupedOptionSet(\SimpleXMLElement $fieldXML, string $value, string $langView, string $typeName, ?array &$optionArray): void
|
||||
{
|
||||
@@ -927,7 +927,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $order
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function parseGroupLabel(string $option, string $langView, array &$groups, array &$order): void
|
||||
{
|
||||
@@ -950,7 +950,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function parseGroupedOption(string $option, string $langView, array &$grouped, array &$order, ?array &$optionArray): void
|
||||
{
|
||||
@@ -988,7 +988,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array|null $optionArray
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function parsePlainGroupedOption(string $option, string $langView, array &$grouped, array &$order, ?array &$optionArray): void
|
||||
{
|
||||
@@ -1009,7 +1009,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $order
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function appendGroupedOptions(\SimpleXMLElement $fieldXML, array &$groups, array &$grouped, array &$order): void
|
||||
{
|
||||
@@ -1045,7 +1045,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param string|null $exclude
|
||||
*
|
||||
* @return void
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function appendFieldAttributes(\SimpleXMLElement $fieldXML, array $fieldAttributes, ?string $exclude = null): void
|
||||
{
|
||||
@@ -1068,7 +1068,7 @@ final class FieldXML implements Fieldtypeinterface
|
||||
* @param array $link The link data which may contain 'table', 'component', 'view', 'text', and 'id'.
|
||||
*
|
||||
* @return array|null The structured linker relation array, or null if input is an empty array.
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private function setLinkerRelations(array $link): ?array
|
||||
{
|
||||
|
@@ -14,7 +14,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Customcode;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\User\User;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Version;
|
||||
|
@@ -13,7 +13,7 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Customcode\Extractor;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\JsonHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
@@ -178,7 +178,7 @@ class Paths
|
||||
// check if the local install is found
|
||||
foreach ($local_paths as $key => $localPath)
|
||||
{
|
||||
if (!Folder::exists($localPath))
|
||||
if (!is_dir($localPath))
|
||||
{
|
||||
unset($local_paths[$key]);
|
||||
}
|
||||
|
@@ -231,7 +231,7 @@ final class InstallScript implements GetScriptInterface
|
||||
$script = PHP_EOL . 'use Joomla\CMS\Factory;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Language\Text;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Filesystem\File;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Filesystem\Folder;' . PHP_EOL;
|
||||
$script .= PHP_EOL . 'use Joomla\Filesystem\Folder;' . PHP_EOL;
|
||||
$script .= PHP_EOL . '/**';
|
||||
$script .= PHP_EOL . ' * ' . $extension->official_name
|
||||
. ' script file.';
|
||||
|
@@ -231,7 +231,7 @@ final class InstallScript implements GetScriptInterface
|
||||
$script = PHP_EOL . 'use Joomla\CMS\Factory;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Language\Text;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Filesystem\File;';
|
||||
$script .= PHP_EOL . 'use Joomla\CMS\Filesystem\Folder;' . PHP_EOL;
|
||||
$script .= PHP_EOL . 'use Joomla\Filesystem\Folder;' . PHP_EOL;
|
||||
$script .= PHP_EOL . '/**';
|
||||
$script .= PHP_EOL . ' * ' . $extension->official_name
|
||||
. ' script file.';
|
||||
|
@@ -48,6 +48,9 @@ use VDM\Joomla\Componentbuilder\Compiler\Service\ArchitectureComHelperClass;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\ArchitectureController;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\ArchitectureModel;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Service\ArchitecturePlugin;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Git;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Github;
|
||||
use VDM\Joomla\Github\Service\Utilities as GithubUtilities;
|
||||
use VDM\Joomla\Componentbuilder\Service\Gitea;
|
||||
use VDM\Joomla\Gitea\Service\Utilities as GiteaUtilities;
|
||||
use VDM\Joomla\Gitea\Service\Settings as GiteaSettings;
|
||||
@@ -159,6 +162,9 @@ abstract class Factory extends ExtendingFactory implements FactoryInterface
|
||||
->registerServiceProvider(new ArchitectureController())
|
||||
->registerServiceProvider(new ArchitectureModel())
|
||||
->registerServiceProvider(new ArchitecturePlugin())
|
||||
->registerServiceProvider(new Git())
|
||||
->registerServiceProvider(new Github())
|
||||
->registerServiceProvider(new GithubUtilities())
|
||||
->registerServiceProvider(new Gitea())
|
||||
->registerServiceProvider(new GiteaUtilities())
|
||||
->registerServiceProvider(new GiteaSettings())
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaFive;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreFieldInterface;
|
||||
|
||||
@@ -99,7 +99,7 @@ final class CoreField implements CoreFieldInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaFive;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreRuleInterface;
|
||||
|
||||
@@ -95,7 +95,7 @@ final class CoreRule implements CoreRuleInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaFour;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreFieldInterface;
|
||||
|
||||
@@ -99,7 +99,7 @@ final class CoreField implements CoreFieldInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaFour;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreRuleInterface;
|
||||
|
||||
@@ -95,7 +95,7 @@ final class CoreRule implements CoreRuleInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaThree;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreFieldInterface;
|
||||
|
||||
@@ -100,7 +100,7 @@ final class CoreField implements CoreFieldInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Field\JoomlaThree;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Field\CoreRuleInterface;
|
||||
|
||||
@@ -95,7 +95,7 @@ final class CoreRule implements CoreRuleInterface
|
||||
private function set(string $path): void
|
||||
{
|
||||
// Check if the path exists
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
@@ -19,7 +19,7 @@ use VDM\Joomla\Componentbuilder\Compiler\Builder\ContentMulti;
|
||||
/**
|
||||
* Compiler Field Modal Select
|
||||
*
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class ModalSelect
|
||||
{
|
||||
@@ -27,7 +27,7 @@ final class ModalSelect
|
||||
* The Structure Class.
|
||||
*
|
||||
* @var Structure
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Structure $structure;
|
||||
|
||||
@@ -35,7 +35,7 @@ final class ModalSelect
|
||||
* The ContentMulti Class.
|
||||
*
|
||||
* @var ContentMulti
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected ContentMulti $contentmulti;
|
||||
|
||||
@@ -43,7 +43,7 @@ final class ModalSelect
|
||||
* The switch to ensure the fix is just added once
|
||||
*
|
||||
* @var bool
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected bool $addedFix = false;
|
||||
|
||||
@@ -53,7 +53,7 @@ final class ModalSelect
|
||||
* @param Structure $structure The Structure Class.
|
||||
* @param ContentMulti $contentmulti The ContentMulti Class.
|
||||
*
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(Structure $structure, ContentMulti $contentmulti)
|
||||
{
|
||||
|
@@ -14,8 +14,8 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Helper;
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\File;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
|
@@ -1071,7 +1071,7 @@ class Get
|
||||
}
|
||||
CFactory::_('Config')->set('field_builder_type', $this->fieldBuilderType);
|
||||
// load the compiler path @deprecated
|
||||
$this->compilerPath = CFactory::_('Config')->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler');
|
||||
$this->compilerPath = CFactory::_('Config')->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler');
|
||||
// load the jcb powers path @deprecated
|
||||
$this->jcbPowersPath = CFactory::_('Config')->get('jcb_powers_path', 'libraries/jcb_powers');
|
||||
// set the component ID @deprecated
|
||||
|
@@ -13,8 +13,8 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Helper;
|
||||
|
||||
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\File;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\Filter\OutputFilter;
|
||||
use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper;
|
||||
use VDM\Joomla\Utilities\StringHelper;
|
||||
@@ -2524,7 +2524,7 @@ class Infusion extends Interpretation
|
||||
// build the path to place the lang file
|
||||
$path = CFactory::_('Utilities.Paths')->component_path . '/' . $p . '/language/'
|
||||
. $tag . '/';
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
// count the folder created
|
||||
|
@@ -12,8 +12,8 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Helper;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\File;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Component\Componentbuilder\Administrator\Helper\ComponentbuilderHelper;
|
||||
use VDM\Joomla\FOF\Encrypt\AES;
|
||||
@@ -324,10 +324,13 @@ class Interpretation extends Fields
|
||||
{
|
||||
// the text for the file BAKING
|
||||
CFactory::_('Compiler.Builder.Content.Multi')->set('emailer_' . $component . '|BAKING', ''); // <<-- to insure it gets updated
|
||||
// return the code need to load the abstract class
|
||||
return PHP_EOL . "\JLoader::register('" . $Component
|
||||
. "Email', JPATH_COMPONENT_ADMINISTRATOR . '/helpers/"
|
||||
. $component . "email.php'); ";
|
||||
if (CFactory::_('Config')->get('joomla_version', 3) == 3)
|
||||
{
|
||||
// return the code need to load the abstract class
|
||||
return PHP_EOL . "\JLoader::register('" . $Component
|
||||
. "Email', JPATH_ADMINISTRATOR . '/components/com_{$component}/helpers/"
|
||||
. $component . "email.php'); ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -935,29 +938,6 @@ class Interpretation extends Fields
|
||||
$function[] = Indent::_(3) . "}";
|
||||
$function[] = Indent::_(2) . "}";
|
||||
}
|
||||
// add the whmcs option
|
||||
if (CFactory::_('Compiler.Builder.Model.Whmcs.Field')->isActive()
|
||||
|| CFactory::_('Component')->get('add_license'))
|
||||
{
|
||||
$function[] = Indent::_(2) . "//" . Line::_(__Line__, __Class__)
|
||||
. " WHMCS Encryption Type";
|
||||
$function[] = Indent::_(2)
|
||||
. "if ('whmcs' === \$type || 'advanced' === \$type)";
|
||||
$function[] = Indent::_(2) . "{";
|
||||
$function[] = Indent::_(3)
|
||||
. "\$key = \$params->get('whmcs_key', \$default);";
|
||||
$function[] = Indent::_(3) . "if (Super_" . "__1f28cb53_60d9_4db1_b517_3c7dc6b429ef___Power::check(\$key))";
|
||||
$function[] = Indent::_(3) . "{";
|
||||
$function[] = Indent::_(4) . "//" . Line::_(__Line__, __Class__)
|
||||
. " load the file";
|
||||
$function[] = Indent::_(4)
|
||||
. "JLoader::import( 'whmcs', JPATH_COMPONENT_ADMINISTRATOR);";
|
||||
$function[] = PHP_EOL . Indent::_(4)
|
||||
. "\$the = new \WHMCS(\$key);";
|
||||
$function[] = PHP_EOL . Indent::_(4) . "return \$the->_key;";
|
||||
$function[] = Indent::_(3) . "}";
|
||||
$function[] = Indent::_(2) . "}";
|
||||
}
|
||||
// end the function
|
||||
$function[] = PHP_EOL . Indent::_(2) . "return \$default;";
|
||||
$function[] = Indent::_(1) . "}";
|
||||
@@ -991,7 +971,7 @@ class Interpretation extends Fields
|
||||
. "\$path = '/'. trim(str_replace('//', '/', \$path), '/');";
|
||||
$function[] = Indent::_(2) . "//" . Line::_(__Line__, __Class__)
|
||||
. " Check if folder exist";
|
||||
$function[] = Indent::_(2) . "if (!Folder::exists(\$path))";
|
||||
$function[] = Indent::_(2) . "if (!is_dir(\$path))";
|
||||
$function[] = Indent::_(2) . "{";
|
||||
$function[] = Indent::_(3) . "//" . Line::_(__Line__, __Class__)
|
||||
. " Lock key.";
|
||||
@@ -5787,7 +5767,7 @@ class Interpretation extends Fields
|
||||
__LINE__,__CLASS__
|
||||
) . " add the google chart builder class.";
|
||||
$chart[] = Indent::_(2)
|
||||
. "require_once JPATH_COMPONENT_ADMINISTRATOR.'/helpers/chartbuilder.php';";
|
||||
. "require_once JPATH_ADMINISTRATOR . '/components/com_" . CFactory::_('Config')->component_code_name . "/helpers/chartbuilder.php';";
|
||||
$chart[] = Indent::_(2) . "//" . Line::_(__Line__, __Class__)
|
||||
. " load the google chart js.";
|
||||
$chart[] = Indent::_(2)
|
||||
@@ -5837,12 +5817,12 @@ class Interpretation extends Fields
|
||||
if (CFactory::_('Config')->build_target === 'site')
|
||||
{
|
||||
$setter .= PHP_EOL . Indent::_(2)
|
||||
. "require_once( JPATH_COMPONENT_SITE.'/helpers/headercheck.php' );";
|
||||
. "require_once( JPATH_SITE . '/components/com_" . CFactory::_('Config')->component_code_name . "/helpers/headercheck.php' );";
|
||||
}
|
||||
else
|
||||
{
|
||||
$setter .= PHP_EOL . Indent::_(2)
|
||||
. "require_once( JPATH_COMPONENT_ADMINISTRATOR.'/helpers/headercheck.php' );";
|
||||
. "require_once( JPATH_ADMINISTRATOR . '/components/com_" . CFactory::_('Config')->component_code_name . "/helpers/headercheck.php' );";
|
||||
}
|
||||
$setter .= PHP_EOL . Indent::_(2) . "//" . Line::_(__Line__, __Class__)
|
||||
. " Initialize the header checker.";
|
||||
@@ -23310,7 +23290,7 @@ class Interpretation extends Fields
|
||||
// set path
|
||||
$path = $module->folder_path . '/language/' . $tag . '/';
|
||||
// create path if not exist
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
// count the folder created
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Helper;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\File;
|
||||
use Joomla\Filesystem\File;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use VDM\Joomla\Utilities\ArrayHelper;
|
||||
use VDM\Joomla\Utilities\GetHelper;
|
||||
|
@@ -506,7 +506,7 @@ final class Header implements HeaderInterface
|
||||
case 'import.model':
|
||||
$headers[] = 'use Joomla\Filesystem\File;';
|
||||
$headers[] = 'use Joomla\Filesystem\Folder;';
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\Path;';
|
||||
$headers[] = 'use Joomla\Filesystem\Path;';
|
||||
$headers[] = 'use Joomla\CMS\Filter\OutputFilter;';
|
||||
$headers[] = 'use Joomla\CMS\Installer\InstallerHelper;';
|
||||
$headers[] = 'use Joomla\CMS\MVC\Model\BaseDatabaseModel;';
|
||||
|
@@ -505,7 +505,7 @@ final class Header implements HeaderInterface
|
||||
case 'import.custom.model':
|
||||
case 'import.model':
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\File;';
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\Folder;';
|
||||
$headers[] = 'use Joomla\Filesystem\Folder;';
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\Path;';
|
||||
$headers[] = 'use Joomla\CMS\Filter\OutputFilter;';
|
||||
$headers[] = 'use Joomla\CMS\Installer\InstallerHelper;';
|
||||
|
@@ -388,7 +388,7 @@ final class Header implements HeaderInterface
|
||||
case 'import.custom.model':
|
||||
case 'import.model':
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\File;';
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\Folder;';
|
||||
$headers[] = 'use Joomla\Filesystem\Folder;';
|
||||
$headers[] = 'use Joomla\CMS\Filesystem\Path;';
|
||||
$headers[] = 'use Joomla\CMS\Filter\OutputFilter;';
|
||||
$headers[] = 'use Joomla\CMS\Installer\InstallerHelper;';
|
||||
|
@@ -350,7 +350,7 @@ class Structure
|
||||
*/
|
||||
protected function modulePath(object &$module): void
|
||||
{
|
||||
$module->folder_path = $this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
|
||||
$module->folder_path = $this->config->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler') . '/'
|
||||
. $module->folder_name;
|
||||
}
|
||||
|
||||
|
@@ -321,7 +321,7 @@ class Structure implements StructureInterface
|
||||
*/
|
||||
protected function pluginPath(object &$plugin): void
|
||||
{
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler') . '/'
|
||||
. $plugin->folder_name;
|
||||
}
|
||||
|
||||
|
@@ -321,7 +321,7 @@ class Structure implements StructureInterface
|
||||
*/
|
||||
protected function pluginPath(object &$plugin): void
|
||||
{
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler') . '/'
|
||||
. $plugin->folder_name;
|
||||
}
|
||||
|
||||
|
@@ -282,7 +282,7 @@ class Structure implements StructureInterface
|
||||
*/
|
||||
protected function pluginPath(object &$plugin): void
|
||||
{
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_COMPONENT_ADMINISTRATOR . '/compiler') . '/'
|
||||
$plugin->folder_path = $this->config->get('compiler_path', JPATH_ADMINISTRATOR . '/components/com_componentbuilder/compiler') . '/'
|
||||
. $plugin->folder_name;
|
||||
}
|
||||
|
||||
|
@@ -54,141 +54,143 @@ final class Purge
|
||||
}
|
||||
|
||||
/**
|
||||
* Purge the unused language strings.
|
||||
* Purge unused language strings linked to a component.
|
||||
*
|
||||
* This method removes or updates language strings that are no longer linked
|
||||
* to the specified component. It checks if the strings are linked to other
|
||||
* extensions and either updates, archives, or deletes them based on the
|
||||
* conditions.
|
||||
*
|
||||
* @param array $values The active strings.
|
||||
* @param int $targetGuid The target entity GUID.
|
||||
* @param string $target The target extension type (default is 'components').
|
||||
* @param array $values Active string sources.
|
||||
* @param string $targetGuid The GUID of the target entity.
|
||||
* @param string $target Target extension type. Default: 'components'.
|
||||
*
|
||||
* @return void
|
||||
* @since 5.0.2
|
||||
*/
|
||||
public function execute(array $values, string $targetGuid, string $target = 'components'): void
|
||||
{
|
||||
$target_types = ['components' => 'components', 'modules' => 'modules', 'plugins' => 'plugins'];
|
||||
$validTargets = ['components' => 'components', 'modules' => 'modules', 'plugins' => 'plugins'];
|
||||
|
||||
if (isset($target_types[$target]))
|
||||
if (!isset($validTargets[$target]))
|
||||
{
|
||||
unset($target_types[$target]);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a new query object.
|
||||
$query = $this->db->getQuery(true);
|
||||
$query->from($this->db->quoteName('#__componentbuilder_language_translation', 'a'))
|
||||
->select($this->db->quoteName(['a.id', 'a.translation', 'a.components', 'a.modules', 'a.plugins']))
|
||||
->where($this->db->quoteName('a.source') . ' NOT IN (' . implode(',', array_map(fn($a) => $this->db->quote($a), $values)) . ')')
|
||||
->where($this->db->quoteName('a.published') . ' = 1');
|
||||
$otherTargets = array_diff_key($validTargets, [$target => $target]);
|
||||
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
$query = $this->db->getQuery(true)
|
||||
->select($this->db->quoteName(['id', 'translation', 'components', 'modules', 'plugins']))
|
||||
->from($this->db->quoteName('#__componentbuilder_language_translation', 'a'))
|
||||
->where($this->db->quoteName('a.source') . ' NOT IN (' . implode(',', array_map([$this->db, 'quote'], $values)) . ')')
|
||||
->where($this->db->quoteName('a.published') . ' = 1');
|
||||
|
||||
if ($this->db->getNumRows())
|
||||
$this->db->setQuery($query);
|
||||
$this->db->execute();
|
||||
|
||||
if (!$this->db->getNumRows())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$today = Factory::getDate()->toSql();
|
||||
$items = $this->db->loadAssocList();
|
||||
$counterUpdate = 0;
|
||||
|
||||
foreach ($items as $item)
|
||||
{
|
||||
if (!JsonHelper::check($item[$target]))
|
||||
{
|
||||
$counterUpdate = 0;
|
||||
$otherStrings = $this->db->loadAssocList();
|
||||
$today = Factory::getDate()->toSql();
|
||||
continue;
|
||||
}
|
||||
|
||||
foreach ($otherStrings as $item)
|
||||
{
|
||||
if (JsonHelper::check($item[$target]))
|
||||
{
|
||||
$targets = (array) json_decode((string) $item[$target], true);
|
||||
$targets = (array) json_decode((string) $item[$target], true);
|
||||
|
||||
if (($key = array_search($targetGuid, $targets)) !== false)
|
||||
{
|
||||
unset($targets[$key]);
|
||||
if (($key = array_search($targetGuid, $targets, true)) === false)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (ArrayHelper::check($targets))
|
||||
{
|
||||
$this->update->set($item['id'], $target, $targets, 1, $today, $counterUpdate);
|
||||
unset($targets[$key]);
|
||||
|
||||
$counterUpdate++;
|
||||
|
||||
$this->update->execute(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->handleUnlinkedString($item, $target_types, $targets, $today, $counterUpdate);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->update->execute();
|
||||
if (ArrayHelper::check($targets))
|
||||
{
|
||||
$this->update->set($item['id'], $target, $targets, 1, $today, $counterUpdate);
|
||||
$counterUpdate++;
|
||||
$this->update->execute(50);
|
||||
}
|
||||
else
|
||||
{
|
||||
$this->handleUnlinkedString($item, $otherTargets, $target, $targets, $today, $counterUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
$this->update->execute();
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle strings that are unlinked from the current component.
|
||||
* Handle strings no longer linked to the current component.
|
||||
*
|
||||
* This method checks if a string is linked to other extensions and either updates,
|
||||
* archives, or deletes it based on the conditions.
|
||||
*
|
||||
* @param array $item The language string item.
|
||||
* @param array $targetTypes The target extension types.
|
||||
* @param array $targets The targets to update.
|
||||
* @param string $today The current date.
|
||||
* @param int $counter The update counter.
|
||||
* @param array $item The language string item.
|
||||
* @param array $otherTypes Other extension types.
|
||||
* @param string $target The current target extension type.
|
||||
* @param array $targets Remaining targets to update.
|
||||
* @param string $today Current date in SQL format.
|
||||
* @param int $counter Counter for updates.
|
||||
*
|
||||
* @return void
|
||||
* @since 5.0.2
|
||||
*/
|
||||
protected function handleUnlinkedString(array $item, array $targetTypes, array $targets, string $today, int &$counter): void
|
||||
protected function handleUnlinkedString(array $item, array $otherTypes, string $target,
|
||||
array $targets, string $today, int &$counter): void
|
||||
{
|
||||
// the action (1 = remove, 2 = archive, 0 = do nothing)
|
||||
$action_with_string = 1;
|
||||
$action = 1; // 1 = remove, 2 = archive, 0 = keep
|
||||
|
||||
foreach ($targetTypes as $other_target)
|
||||
foreach ($otherTypes as $type)
|
||||
{
|
||||
if ($action_with_string && JsonHelper::check($item[$other_target]))
|
||||
if (JsonHelper::check($item[$type]))
|
||||
{
|
||||
$other_targets = (array) json_decode((string) $item[$other_target], true);
|
||||
|
||||
if (ArrayHelper::check($other_targets))
|
||||
$linked = json_decode((string) $item[$type], true);
|
||||
if (ArrayHelper::check($linked))
|
||||
{
|
||||
$action_with_string = 0;
|
||||
$action = 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($action_with_string && JsonHelper::check($item['translation']))
|
||||
if ($action && JsonHelper::check($item['translation']))
|
||||
{
|
||||
$translation = json_decode((string) $item['translation'], true);
|
||||
|
||||
if (ArrayHelper::check($translation))
|
||||
{
|
||||
$this->update->set($item['id'], $targets, $targets, 2, $today, $counter);
|
||||
$this->update->set($item['id'], $target, $targets, 2, $today, $counter);
|
||||
$counter++;
|
||||
$this->update->execute(50);
|
||||
$action_with_string = 2;
|
||||
$action = 2; // just to show intent :)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if ($action_with_string == 1)
|
||||
if ($action === 1)
|
||||
{
|
||||
$this->removeExitingLangString($item['id']);
|
||||
$this->removeLanguageString($item['id']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove existing language translation strings.
|
||||
* Delete a language string by ID.
|
||||
*
|
||||
* This method deletes a language string from the database based on its ID.
|
||||
*
|
||||
* @param int $id The string ID to remove.
|
||||
* @param int $id The ID of the string.
|
||||
*
|
||||
* @return void
|
||||
* @since 5.0.2
|
||||
*/
|
||||
protected function removeExitingLangString(int $id): void
|
||||
protected function removeLanguageString(int $id): void
|
||||
{
|
||||
$query = $this->db->getQuery(true);
|
||||
$query->delete($this->db->quoteName('#__componentbuilder_language_translation'))
|
||||
$query = $this->db->getQuery(true)
|
||||
->delete($this->db->quoteName('#__componentbuilder_language_translation'))
|
||||
->where($this->db->quoteName('id') . ' = ' . (int) $id);
|
||||
|
||||
$this->db->setQuery($query);
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Library;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder as JoomlaFolder;
|
||||
use Joomla\Filesystem\Folder as JoomlaFolder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Config;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Registry;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\EventInterface as Event;
|
||||
@@ -158,7 +158,7 @@ class Structure
|
||||
);
|
||||
|
||||
// creat the main component folder
|
||||
if (!JoomlaFolder::exists($this->paths->component_path))
|
||||
if (!is_dir($this->paths->component_path))
|
||||
{
|
||||
JoomlaFolder::create($this->paths->component_path);
|
||||
|
||||
|
@@ -105,7 +105,9 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
return new Get(
|
||||
$container->get('Joomla.Power.Remote.Config'),
|
||||
$container->get('Joomla.Power.Grep'),
|
||||
$container->get('Data.Item')
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,8 +123,9 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
{
|
||||
return new Grep(
|
||||
$container->get('Joomla.Power.Remote.Config'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Network.Resolve'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Config')->approved_joomla_paths
|
||||
);
|
||||
}
|
||||
|
@@ -16,6 +16,8 @@ use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Power as Powers;
|
||||
use VDM\Joomla\Componentbuilder\Power\Table;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
use VDM\Joomla\Componentbuilder\Package\MessageBus;
|
||||
use VDM\Joomla\Componentbuilder\Power\Remote\Config;
|
||||
use VDM\Joomla\Componentbuilder\Power\Remote\Get;
|
||||
use VDM\Joomla\Componentbuilder\Power\Grep;
|
||||
@@ -53,6 +55,12 @@ class Power implements ServiceProviderInterface
|
||||
$container->alias(Table::class, 'Power.Table')
|
||||
->share('Power.Table', [$this, 'getPowerTable'], true);
|
||||
|
||||
$container->alias(Tracker::class, 'Power.Tracker')
|
||||
->share('Power.Tracker', [$this, 'getPowerTracker'], true);
|
||||
|
||||
$container->alias(MessageBus::class, 'Power.Message')
|
||||
->share('Power.Message', [$this, 'getMessageBus'], true);
|
||||
|
||||
$container->alias(Config::class, 'Power.Remote.Config')
|
||||
->share('Power.Remote.Config', [$this, 'getRemoteConfig'], true);
|
||||
|
||||
@@ -122,6 +130,32 @@ class Power implements ServiceProviderInterface
|
||||
return new Table();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Tracker Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getPowerTracker(Container $container): Tracker
|
||||
{
|
||||
return new Tracker();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Message Bus Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return MessageBus
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getMessageBus(Container $container): MessageBus
|
||||
{
|
||||
return new MessageBus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Remote Config Class.
|
||||
*
|
||||
@@ -150,7 +184,9 @@ class Power implements ServiceProviderInterface
|
||||
return new Get(
|
||||
$container->get('Power.Remote.Config'),
|
||||
$container->get('Power.Grep'),
|
||||
$container->get('Data.Item')
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -166,8 +202,9 @@ class Power implements ServiceProviderInterface
|
||||
{
|
||||
return new Grep(
|
||||
$container->get('Power.Remote.Config'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Network.Resolve'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Config')->approved_paths,
|
||||
$container->get('Config')->local_powers_repository_path
|
||||
);
|
||||
|
@@ -12,7 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\File as JoomlaFile;
|
||||
use Joomla\Filesystem\File as JoomlaFile;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Paths;
|
||||
|
@@ -12,8 +12,8 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Compiler\Utilities;
|
||||
|
||||
|
||||
use Joomla\CMS\Filesystem\Folder as JoomlaFolder;
|
||||
use Joomla\CMS\Filesystem\File as JoomlaFile;
|
||||
use Joomla\Filesystem\Folder as JoomlaFolder;
|
||||
use Joomla\Filesystem\File as JoomlaFile;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Factory as Compiler;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Counter;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\File;
|
||||
@@ -69,7 +69,7 @@ class Folder
|
||||
public function create(string $path, bool $addHtml = true)
|
||||
{
|
||||
// check if the path exist
|
||||
if (!JoomlaFolder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
// create the path
|
||||
JoomlaFolder::create(
|
||||
@@ -100,7 +100,7 @@ class Folder
|
||||
*/
|
||||
public function remove(string $path, ?array $ignore = null): bool
|
||||
{
|
||||
if (!JoomlaFolder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
@@ -15,8 +15,8 @@ namespace VDM\Joomla\Componentbuilder\Compiler\Utilities;
|
||||
use Joomla\CMS\Factory;
|
||||
use Joomla\CMS\Application\CMSApplication;
|
||||
use Joomla\CMS\Language\Text;
|
||||
use Joomla\CMS\Filesystem\File as JoomlaFile;
|
||||
use Joomla\CMS\Filesystem\Folder;
|
||||
use Joomla\Filesystem\File as JoomlaFile;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Placeholder;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Interfaces\Component\SettingsInterface as Settings;
|
||||
use VDM\Joomla\Componentbuilder\Compiler\Utilities\Paths;
|
||||
@@ -208,7 +208,7 @@ class Structure
|
||||
}
|
||||
|
||||
// setup the folder
|
||||
if (!Folder::exists($path))
|
||||
if (!is_dir($path))
|
||||
{
|
||||
Folder::create($path);
|
||||
$this->file->html($zip_path);
|
||||
@@ -219,7 +219,7 @@ class Structure
|
||||
|
||||
$new_name = $this->getNewName($details, $item, $name, $fileName);
|
||||
|
||||
if (!JoomlaFile::exists($path . '/' . $new_name))
|
||||
if (!is_file($path . '/' . $new_name))
|
||||
{
|
||||
// move the file to its place
|
||||
JoomlaFile::copy(
|
||||
|
@@ -664,6 +664,22 @@ final class Guid
|
||||
'array' => false,
|
||||
'valueType' => 1,
|
||||
],
|
||||
[
|
||||
'table' => 'class_method',
|
||||
'column' => 'joomla_plugin_group',
|
||||
'linkedTable' => 'class_property',
|
||||
'linkedColumn' => 'id',
|
||||
'array' => false,
|
||||
'valueType' => 1,
|
||||
],
|
||||
[
|
||||
'table' => 'class_property',
|
||||
'column' => 'joomla_plugin_group',
|
||||
'linkedTable' => 'class_property',
|
||||
'linkedColumn' => 'id',
|
||||
'array' => false,
|
||||
'valueType' => 1,
|
||||
],
|
||||
];
|
||||
|
||||
/**
|
||||
|
@@ -13,10 +13,14 @@ namespace VDM\Joomla\Componentbuilder\Fieldtype;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use VDM\Joomla\Componentbuilder\Fieldtype\Service\Fieldtype as Power;
|
||||
use VDM\Joomla\Componentbuilder\Fieldtype\Service\Fieldtype;
|
||||
use VDM\Joomla\Componentbuilder\Package\Service\Power;
|
||||
use VDM\Joomla\Service\Database;
|
||||
use VDM\Joomla\Service\Model;
|
||||
use VDM\Joomla\Service\Data;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Git;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Github;
|
||||
use VDM\Joomla\Github\Service\Utilities as GithubUtilities;
|
||||
use VDM\Joomla\Componentbuilder\Service\Gitea;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Gitea as GiteaPower;
|
||||
use VDM\Joomla\Gitea\Service\Utilities as GiteaUtilities;
|
||||
@@ -51,10 +55,14 @@ abstract class Factory extends ExtendingFactory implements FactoryInterface
|
||||
protected static function createContainer(): Container
|
||||
{
|
||||
return (new Container())
|
||||
->registerServiceProvider(new Fieldtype())
|
||||
->registerServiceProvider(new Power())
|
||||
->registerServiceProvider(new Database())
|
||||
->registerServiceProvider(new Model())
|
||||
->registerServiceProvider(new Data())
|
||||
->registerServiceProvider(new Git())
|
||||
->registerServiceProvider(new Github())
|
||||
->registerServiceProvider(new GithubUtilities())
|
||||
->registerServiceProvider(new Gitea())
|
||||
->registerServiceProvider(new GiteaPower())
|
||||
->registerServiceProvider(new GiteaUtilities())
|
||||
|
@@ -65,78 +65,66 @@ final class Grep extends ExtendingGrep implements GrepInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a remote joomla power
|
||||
* Get a remote field type object from a repository.
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique id of the power
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique ID of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 5.0.3
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getRemote(object $path, string $guid): ?object
|
||||
{
|
||||
$power = null;
|
||||
if (empty($path->index->{$guid}->path))
|
||||
$relative_path = $path->index[$this->entity]->{$guid}->path ?? null;
|
||||
if (empty($relative_path))
|
||||
{
|
||||
return $power;
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the branch name
|
||||
$branch = $this->getBranchName($path);
|
||||
$branch = $this->getBranchName($path);
|
||||
$guid_field = $this->getGuidField();
|
||||
$settings_name = $this->getSettingsName();
|
||||
$readme_enabled = $this->hasItemReadme();
|
||||
|
||||
// get the guid_field key
|
||||
$guid_field = $this->getGuidField();
|
||||
|
||||
// get the settings path
|
||||
$settings_path = $this->getSettingsPath();
|
||||
// set the target system
|
||||
$target = $path->target ?? 'gitea';
|
||||
$this->contents->setTarget($target);
|
||||
|
||||
// load the base and token if set
|
||||
$this->loadApi($this->contents, $path->base ?? null, $path->token ?? null);
|
||||
$this->loadApi(
|
||||
$this->contents,
|
||||
$target === 'gitea' ? ($path->base ?? null) : null,
|
||||
$path->token ?? null
|
||||
);
|
||||
|
||||
// get the settings
|
||||
if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->path . '/' . $settings_path, $branch)) !== null &&
|
||||
isset($power->{$guid_field}))
|
||||
$power = $this->loadRemoteFile(
|
||||
$path->organisation,
|
||||
$path->repository,
|
||||
"{$relative_path}/{$settings_name}",
|
||||
$branch
|
||||
);
|
||||
|
||||
if ($power === null || !isset($power->{$guid_field}))
|
||||
{
|
||||
// set the git details in params
|
||||
$path_guid = $path->guid ?? null;
|
||||
if ($path_guid !== null)
|
||||
$this->contents->reset_();
|
||||
return null;
|
||||
}
|
||||
|
||||
$path_guid = $path->guid ?? null;
|
||||
|
||||
$branch_field = $this->getBranchField();
|
||||
|
||||
if ($branch_field === 'write_branch' && $path_guid !== null)
|
||||
{
|
||||
$this->setRepoItemSha($power, $path, "{$relative_path}/{$settings_name}", $branch, "{$path_guid}-settings");
|
||||
|
||||
if ($readme_enabled)
|
||||
{
|
||||
// get the Settings meta
|
||||
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/' . $settings_path, $branch)) !== null &&
|
||||
isset($meta->sha))
|
||||
{
|
||||
if (isset($power->params) && is_object($power->params) &&
|
||||
isset($power->params->source) && is_array($power->params->source))
|
||||
{
|
||||
$power->params->source[$path_guid . '-settings'] = $meta->sha;
|
||||
}
|
||||
else
|
||||
{
|
||||
$power->params = (object) [
|
||||
'source' => [$path_guid . '-settings' => $meta->sha]
|
||||
];
|
||||
}
|
||||
}
|
||||
// get the README meta
|
||||
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/README.md', $branch)) !== null &&
|
||||
isset($meta->sha))
|
||||
{
|
||||
if (isset($power->params) && is_object($power->params) &&
|
||||
isset($power->params->source) && is_array($power->params->source))
|
||||
{
|
||||
$power->params->source[$path_guid . '-readme'] = $meta->sha;
|
||||
}
|
||||
else
|
||||
{
|
||||
$power->params = (object) [
|
||||
'source' => [$path_guid . '-readme' => $meta->sha]
|
||||
];
|
||||
}
|
||||
}
|
||||
$readme_name = $this->getItemReadmeName();
|
||||
$this->setRepoItemSha($power, $path, "{$relative_path}/{$readme_name}", $branch, "{$path_guid}-readme");
|
||||
}
|
||||
}
|
||||
|
||||
// reset back to the global base and token
|
||||
$this->contents->reset_();
|
||||
|
||||
return $power;
|
||||
|
@@ -23,56 +23,135 @@ use VDM\Joomla\Interfaces\Readme\ItemInterface;
|
||||
final class Item implements ItemInterface
|
||||
{
|
||||
/**
|
||||
* Get an item readme
|
||||
* Generate a README for a JCB Field Type in Markdown format.
|
||||
*
|
||||
* @param object $item An item details.
|
||||
* This includes the field type name, short and full description, and a table of properties if available.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @param object $item The field type definition object.
|
||||
*
|
||||
* @return string The generated README as Markdown.
|
||||
* @since 5.0.3
|
||||
*/
|
||||
public function get(object $item): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
|
||||
███████╗██╗███████╗██╗ ██████╗ ████████╗██╗ ██╗██████╗ ███████╗
|
||||
██╔════╝██║██╔════╝██║ ██╔══██╗ ╚══██╔══╝╚██╗ ██╔╝██╔══██╗██╔════╝
|
||||
█████╗ ██║█████╗ ██║ ██║ ██║ ██║ ╚████╔╝ ██████╔╝█████╗
|
||||
██╔══╝ ██║██╔══╝ ██║ ██║ ██║ ██║ ╚██╔╝ ██╔═══╝ ██╔══╝
|
||||
██║ ██║███████╗███████╗██████╔╝ ██║ ██║ ██║ ███████╗
|
||||
╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝
|
||||
```"];
|
||||
// system name
|
||||
$readme[] = "# " . $item->name;
|
||||
$readme = [];
|
||||
|
||||
// Title and system name
|
||||
$readme[] = '### JCB! Field Type';
|
||||
$readme[] = '# ' . ($item->name ?? 'error: missing field type name');
|
||||
$readme[] = '';
|
||||
|
||||
// Short description
|
||||
if (!empty($item->short_description)) {
|
||||
$readme[] = '> ' . trim($item->short_description);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
// Full description
|
||||
if (!empty($item->description))
|
||||
{
|
||||
$readme[] = "\n" . $item->description;
|
||||
$readme[] = trim($item->description);
|
||||
$readme[] = '';
|
||||
}
|
||||
elseif (!empty($item->short_description))
|
||||
|
||||
// Properties table
|
||||
if (!empty($item->properties) && (is_array($item->properties) || is_object($item->properties)))
|
||||
{
|
||||
$readme[] = "\n" . $item->short_description;
|
||||
$readme[] = $this->buildPropertyTable($item->properties);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
$readme[] = "\nThe Joomla! field type within this repository provide an essential mechanism for integrating Joomla-related field type into the Joomla Component Builder (JCB). Each field type is meticulously designed to ensure compatibility and ease of use within the JCB framework, allowing developers to effortlessly incorporate and manage custom fields in their components. By utilizing the reset functionality, users can seamlessly update individual field types to align with the latest versions maintained in our core repository, ensuring that their projects benefit from the most up-to-date features and fixes.\n\nAdditionally, for those who prefer a more personalized approach, the repository can be forked, enabling developers to maintain and distribute their customized field types independently from the broader JCB community. This level of flexibility underscores the open-source nature of JCB, offering you the freedom to adapt and extend your components according to your specific needs, while still benefiting from a robust, community-driven ecosystem.";
|
||||
// Footer
|
||||
$readme[] = '> Integrate, customize, and update this JCB Fieldtype with ease through JCB\'s flexible ecosystem.';
|
||||
$readme[] = '';
|
||||
|
||||
$readme[] = <<<MD
|
||||
### Used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗██████╗
|
||||
██║██╔════╝██╔══██╗
|
||||
██║██║ ██████╔╝
|
||||
██ ██║██║ ██╔══██╗
|
||||
╚█████╔╝╚██████╗██████╔╝
|
||||
╚════╝ ╚═════╝╚═════╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Markdown table with details about each form property, including optional PHP code blocks.
|
||||
*
|
||||
* The table includes columns: Property, Example, Adjustable, Mandatory, and Description.
|
||||
* If the 'example' field contains PHP code patterns like variable assignment or object access,
|
||||
* it will be linked to an anchor section with the code shown below the table.
|
||||
* All '|' characters in example and description fields are replaced with '|' to prevent Markdown table breaking.
|
||||
*
|
||||
* @param array|object $properties Associative array of property objects.
|
||||
*
|
||||
* @return string The generated Markdown output.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function buildPropertyTable(array|object $properties): string
|
||||
{
|
||||
$properties = (array) $properties;
|
||||
$markdown = [];
|
||||
$codeSnippets = [];
|
||||
|
||||
// Table header
|
||||
$markdown[] = '| Property | Example | Adjustable | Mandatory | Description |';
|
||||
$markdown[] = '|----------|---------|------------|-----------|-------------|';
|
||||
|
||||
foreach ($properties as $prop)
|
||||
{
|
||||
$prop = (array) $prop;
|
||||
|
||||
$name = $prop['name'] ?? '—';
|
||||
$example = trim($prop['example'] ?? '');
|
||||
$description = trim($prop['description'] ?? '');
|
||||
|
||||
// Replace "|" in raw content to prevent Markdown table breakage
|
||||
$name = str_replace('|', '|', $name);
|
||||
$example = str_replace('|', '|', $example);
|
||||
$description = str_replace('|', '|', $description);
|
||||
|
||||
$adjustable = (!empty($prop['adjustable']) && $prop['adjustable'] == '1')
|
||||
? ''
|
||||
: '';
|
||||
|
||||
$mandatory = (!empty($prop['mandatory']) && $prop['mandatory'] == '1')
|
||||
? ''
|
||||
: '';
|
||||
|
||||
// Detect PHP-like code: variable assignment or object access
|
||||
$isCode = preg_match('/\$\w+\s*=|\$\w+->\w+/', $example);
|
||||
|
||||
if ($isCode)
|
||||
{
|
||||
$anchor = 'code-' . preg_replace('/[^a-z0-9]+/i', '-', strtolower($name));
|
||||
$link = "[code](#{$anchor})";
|
||||
$codeSnippets[$anchor] = $prop['example'];
|
||||
$example = $link;
|
||||
}
|
||||
elseif ($example === '')
|
||||
{
|
||||
$example = '—';
|
||||
}
|
||||
|
||||
$markdown[] = "| {$name} | {$example} | {$adjustable} | {$mandatory} | {$description} |";
|
||||
}
|
||||
|
||||
// Join the table
|
||||
$output = implode("\n", $markdown);
|
||||
|
||||
// Add code blocks if any
|
||||
if (!empty($codeSnippets))
|
||||
{
|
||||
$output .= "\n\n";
|
||||
foreach ($codeSnippets as $anchor => $code)
|
||||
{
|
||||
$output .= "### <a id=\"{$anchor}\"></a>Code for `{$anchor}`\n\n";
|
||||
$output .= "```php\n{$code}\n```\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -13,6 +13,7 @@ namespace VDM\Joomla\Componentbuilder\Fieldtype\Readme;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Readme\MainInterface;
|
||||
use VDM\Joomla\Componentbuilder\Package\Readme\Main as ExtendingMain;
|
||||
|
||||
|
||||
/**
|
||||
@@ -20,215 +21,95 @@ use VDM\Joomla\Interfaces\Readme\MainInterface;
|
||||
*
|
||||
* @since 5.0.3
|
||||
*/
|
||||
final class Main implements MainInterface
|
||||
final class Main extends ExtendingMain implements MainInterface
|
||||
{
|
||||
/**
|
||||
* Get Main Readme
|
||||
* Generate the main README for the JCB Field Types repository in Markdown format.
|
||||
*
|
||||
* @param array $items All items of this repository.
|
||||
* Field Types define reusable templates for Joomla form fields inside JCB. Each field type links directly
|
||||
* to Joomla's native XML field structure and allows easy reuse of predefined properties across multiple fields.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
* @param array $items All field types currently stored in the repository.
|
||||
*
|
||||
* @return string The full generated Markdown README.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(array $items): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
$readme = [];
|
||||
|
||||
███████╗██╗███████╗██╗ ██████╗ ████████╗██╗ ██╗██████╗ ███████╗███████╗
|
||||
██╔════╝██║██╔════╝██║ ██╔══██╗ ╚══██╔══╝╚██╗ ██╔╝██╔══██╗██╔════╝██╔════╝
|
||||
█████╗ ██║█████╗ ██║ ██║ ██║ ██║ ╚████╔╝ ██████╔╝█████╗ ███████╗
|
||||
██╔══╝ ██║██╔══╝ ██║ ██║ ██║ ██║ ╚██╔╝ ██╔═══╝ ██╔══╝ ╚════██║
|
||||
██║ ██║███████╗███████╗██████╔╝ ██║ ██║ ██║ ███████╗███████║
|
||||
╚═╝ ╚═╝╚══════╝╚══════╝╚═════╝ ╚═╝ ╚═╝ ╚═╝ ╚══════╝╚══════╝
|
||||
```"];
|
||||
// Header
|
||||
$readme[] = '# JCB! Field Types';
|
||||
$readme[] = '';
|
||||
|
||||
// default description of super powers
|
||||
$readme[] = "\n### What is JCB Joomla Field Types?\nThe Joomla field types provide a powerful way to map Joomla-related field types, enabling seamless integration with Joomla Component Builder (JCB). This repository serves as a centralized system for maintaining, updating, and distributing these field types throughout the JCB ecosystem.\n
|
||||
\n
|
||||
When you need to update any field type in JCB, simply select the desired field type and click the \"reset\" button. This action will automatically sync the selected field type with its corresponding version hosted in our core repository, ensuring you always have the latest updates.\n
|
||||
\n
|
||||
Moreover, if you wish to tailor the field types to your specific needs, you can fork the repository and point your JCB instance to your fork. This allows you to maintain and update field types independently from the main JCB community, offering the flexibility that is at the heart of open-source philosophy.\n
|
||||
\n
|
||||
We believe this approach empowers you to extend and customize JCB to fit your unique requirements, exemplifying the true spirit of freedom in software development. We trust you will find this capability both useful and aligned with the expectations of how open-source software should function.\n";
|
||||
// What is it?
|
||||
$readme[] = '### What Are JCB Field Types?';
|
||||
$readme[] = <<<MD
|
||||
JCB Field Types act as **blueprints for Joomla form fields**.
|
||||
Each Field Type defines the structure, rules, and properties (such as required, translatable, adjustable) of a Joomla-compatible field.
|
||||
|
||||
// get the readme body
|
||||
$readme[] = $this->readmeBuilder($items);
|
||||
Instead of manually building repetitive XML field definitions, Field Types allow you to define:
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗ ███╗ ██╗███████╗███╗ ██╗████████╗
|
||||
██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗████╗ ██║██╔════╝████╗ ██║╚══██╔══╝
|
||||
██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║██╔██╗ ██║█████╗ ██╔██╗ ██║ ██║
|
||||
██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║ ██║██║╚██╗██║██╔══╝ ██║╚██╗██║ ██║
|
||||
╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚██████╔╝██║ ╚████║███████╗██║ ╚████║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═══╝ ╚═╝
|
||||
██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗
|
||||
██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗
|
||||
██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝
|
||||
██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗
|
||||
██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
- **Input Types** (`text`, `list`, `radio`, etc.)
|
||||
- **Field Parameters** (`required`, `label`, `description`, etc.)
|
||||
- **Default Values and Validation**
|
||||
- **Custom Logic and Layout Overrides**
|
||||
|
||||
These definitions are stored centrally and reused across all fields built in JCB.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
$readme[] = '### Why Use Field Types?';
|
||||
$readme[] = <<<MD
|
||||
When you create a new Field in JCB, you start by selecting a Field Type.
|
||||
This selection **automatically inherits all the structure and metadata** you defined in the Field Type.
|
||||
|
||||
This templating system:
|
||||
|
||||
- Saves time and reduces duplication
|
||||
- Keeps your form field definitions consistent
|
||||
- Ensures compatibility with Joomla's XML-based field system
|
||||
- Allows global updates to propagate to all child fields
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
$readme[] = '### How Do Field Types Integrate with Joomla?';
|
||||
$readme[] = <<<MD
|
||||
Each Field Type generates **conventional Joomla XML**, which Joomla uses to automatically render HTML forms in both admin and site interfaces.
|
||||
The entire workflow is standards-based — meaning what JCB builds, Joomla understands and renders as expected.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
$readme[] = '### Customization & Syncing';
|
||||
$readme[] = <<<MD
|
||||
Field Types are version-controlled and centrally managed.
|
||||
|
||||
- To **update a field type** from this repository in your JCB instance, simply use the `Reset` button inside the JCB GUI of field types.
|
||||
- You can also **fork this repository** and point your JCB to your fork — giving you full control and independence from upstream updates.
|
||||
|
||||
This design promotes **collaborative sharing** while allowing **custom autonomy**.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
$readme[] = '### Index of JCB Field Types';
|
||||
$readme[] = '';
|
||||
|
||||
// Field type listing
|
||||
$readme[] = $this->getIndex($items);
|
||||
$readme[] = '';
|
||||
|
||||
$readme[] = <<<MD
|
||||
### All used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
||||
/**
|
||||
* The readme builder
|
||||
*
|
||||
* @param array $classes The powers.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function readmeBuilder(array &$items): string
|
||||
{
|
||||
$classes = [];
|
||||
foreach ($items as $guid => $power)
|
||||
{
|
||||
// add to the sort bucket
|
||||
$classes[] = [
|
||||
'name' => $power['name'],
|
||||
'link' => $this->indexLinkPower($power)
|
||||
];
|
||||
}
|
||||
|
||||
return $this->readmeModel($classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort and model the readme classes
|
||||
*
|
||||
* @param array $classes The powers.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function readmeModel(array &$classes): string
|
||||
{
|
||||
$this->sortClasses($classes);
|
||||
|
||||
return $this->generateIndex($classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the index string for classes
|
||||
*
|
||||
* @param array $classes The sorted classes
|
||||
*
|
||||
* @return string The index string
|
||||
*/
|
||||
private function generateIndex(array &$classes): string
|
||||
{
|
||||
$result = "# Index of Joomla! Field Types\n";
|
||||
|
||||
foreach ($classes as $class)
|
||||
{
|
||||
// Add the class details
|
||||
$result .= "\n - " . $class['link'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the flattened array using a single sorting function
|
||||
*
|
||||
* @param array $classes The classes to sort
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function sortClasses(array &$classes): void
|
||||
{
|
||||
usort($classes, function ($a, $b) {
|
||||
return $this->compareName($a, $b);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the name of two classes
|
||||
*
|
||||
* @param array $a First class
|
||||
* @param array $b Second class
|
||||
*
|
||||
* @return int Comparison result
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function compareName(array $a, array $b): int
|
||||
{
|
||||
return strcmp($a['name'], $b['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function indexLinkPower(array &$power): string
|
||||
{
|
||||
$name = $power['name'] ?? 'error';
|
||||
return '**' . $name . "** | "
|
||||
. $this->linkPowerRepo($power) . ' | '
|
||||
. $this->linkPowerSettings($power) . ' | '
|
||||
. $this->linkPowerDesc($power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerRepo(array &$power): string
|
||||
{
|
||||
$path = $power['path'] ?? 'error';
|
||||
return '[Details](' . $path . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power settings in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerSettings(array &$power): string
|
||||
{
|
||||
$settings = $power['settings'] ?? 'error';
|
||||
return '[Settings](' . $settings . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the short description
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerDesc(array &$power): string
|
||||
{
|
||||
$jpk = $power['desc'] ?? '';
|
||||
return $jpk;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -56,67 +56,27 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
protected string $suffix_key = '';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
* The ignore fields
|
||||
*
|
||||
* @var string
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
// [DEFAULT] protected string $main_readme_path = 'README.md';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
// [DEFAULT] protected string $index_path = 'index.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
// [DEFAULT] protected string $src_path = 'src';
|
||||
|
||||
/**
|
||||
* The item settings file path
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
// [DEFAULT] protected string $settings_path = 'item.json';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
// [DEFAULT] protected string $guid_field = 'guid';
|
||||
|
||||
/**
|
||||
* The item map
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
protected array $map = [];
|
||||
[DEFAULT] */
|
||||
protected array $ignore = ['catid', 'access'];
|
||||
|
||||
/**
|
||||
* The index map
|
||||
* must always have: [name,path,guid]
|
||||
* must always have: [name,path,settings,guid]
|
||||
* you can add more
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected array $index_map = [
|
||||
'name' => 'index_map_IndexName',
|
||||
'desc' => 'index_map_ShortDescription',
|
||||
'settings' => 'index_map_IndexSettingsPath',
|
||||
'path' => 'index_map_IndexPath',
|
||||
'guid' => 'index_map_IndexGUID'
|
||||
'settings' => 'index_map_IndexSettingsPath',
|
||||
'guid' => 'index_map_IndexGUID',
|
||||
'desc' => 'index_map_ShortDescription'
|
||||
];
|
||||
|
||||
/**
|
||||
@@ -134,21 +94,9 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
'name',
|
||||
'desc',
|
||||
'path',
|
||||
'settings',
|
||||
'guid',
|
||||
'local'
|
||||
];
|
||||
|
||||
/**
|
||||
* Core Placeholders
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
protected array $placeholders = [
|
||||
'[['.'[NamespacePrefix]]]' => 'VDM',
|
||||
'[['.'[ComponentNamespace]]]' => 'Componentbuilder',
|
||||
'[['.'[Component]]]' => 'Componentbuilder',
|
||||
'[['.'[component]]]' => 'componentbuilder'
|
||||
];
|
||||
[DEFAULT] */
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -55,7 +55,9 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
json_encode($item, JSON_PRETTY_PRINT), // The file content.
|
||||
'Update ' . $item->name, // The commit message.
|
||||
$sha, // The blob SHA of the old file.
|
||||
$repo->write_branch // The branch name.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
|
||||
$success = is_object($result);
|
||||
@@ -85,7 +87,9 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$this->index_map_IndexSettingsPath($item), // The file path.
|
||||
json_encode($item, JSON_PRETTY_PRINT), // The file content.
|
||||
'Create ' . $item->name, // The commit message.
|
||||
$repo->write_branch // The branch name.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
|
||||
return is_object($result);
|
||||
@@ -113,11 +117,13 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$this->git->update(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexPath($item) . '/README.md', // The file path.
|
||||
$this->index_map_IndexReadmePath($item), // The file path.
|
||||
$this->itemReadme->get($item), // The file content.
|
||||
'Update ' . $item->name . ' readme file', // The commit message.
|
||||
'Update ' . ($this->index_map_IndexName($item) ?? 'fieldtype') . ' readme file', // The commit message.
|
||||
$sha, // The blob SHA of the old file.
|
||||
$repo->write_branch // The branch name.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,10 +141,12 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$this->git->create(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexPath($item) . '/README.md', // The file path.
|
||||
$this->index_map_IndexReadmePath($item), // The file path.
|
||||
$this->itemReadme->get($item), // The file content.
|
||||
'Create ' . $item->name . ' readme file', // The commit message.
|
||||
$repo->write_branch // The branch name.
|
||||
'Create ' . ($this->index_map_IndexName($item) ?? 'fieldtype') . ' readme file', // The commit message.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
}
|
||||
|
||||
@@ -160,14 +168,18 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
/**
|
||||
* Get the item Short Description for the index values
|
||||
*
|
||||
* @param object $item
|
||||
* @param object $item The item object to extract description from.
|
||||
*
|
||||
* @return string|null
|
||||
* @return string|null The trimmed short or fallback description, or null if both are empty.
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected function index_map_ShortDescription(object $item): ?string
|
||||
{
|
||||
return $item->short_description ?? $item->description ?? null;
|
||||
$description = $item->short_description ?? $item->description ?? '';
|
||||
|
||||
$description = trim($description);
|
||||
|
||||
return $description !== '' ? $description : null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -15,8 +15,6 @@ namespace VDM\Joomla\Componentbuilder\Fieldtype\Service;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\Fieldtype\Config;
|
||||
use VDM\Joomla\Componentbuilder\Power\Table;
|
||||
use VDM\Joomla\Componentbuilder\Package\MessageBus;
|
||||
use VDM\Joomla\Componentbuilder\Fieldtype\Grep;
|
||||
use VDM\Joomla\Componentbuilder\Fieldtype\Remote\Config as RemoteConfig;
|
||||
use VDM\Joomla\Componentbuilder\Power\Remote\Get;
|
||||
@@ -42,14 +40,8 @@ class Fieldtype implements ServiceProviderInterface
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->alias(Config::class, 'Config')
|
||||
->share('Config', [$this, 'getConfig'], true);
|
||||
|
||||
$container->alias(Table::class, 'Power.Table')->alias('Table', 'Power.Table')
|
||||
->share('Power.Table', [$this, 'getPowerTable'], true);
|
||||
|
||||
$container->alias(MessageBus::class, 'Power.Message')
|
||||
->share('Power.Message', [$this, 'getMessageBus'], true);
|
||||
$container->alias(Config::class, 'Joomla.Fieldtype.Config')->alias('Config', 'Joomla.Fieldtype.Config')
|
||||
->share('Joomla.Fieldtype.Config', [$this, 'getConfig'], true);
|
||||
|
||||
$container->alias(Grep::class, 'Joomla.Fieldtype.Grep')
|
||||
->share('Joomla.Fieldtype.Grep', [$this, 'getGrep'], true);
|
||||
@@ -89,7 +81,7 @@ class Fieldtype implements ServiceProviderInterface
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Table
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getPowerTable(Container $container): Table
|
||||
{
|
||||
@@ -102,7 +94,7 @@ class Fieldtype implements ServiceProviderInterface
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return MessageBus
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getMessageBus(Container $container): MessageBus
|
||||
{
|
||||
@@ -121,9 +113,10 @@ class Fieldtype implements ServiceProviderInterface
|
||||
{
|
||||
return new Grep(
|
||||
$container->get('Joomla.Fieldtype.Remote.Config'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Network.Resolve'),
|
||||
$container->get('Config')->approved_joomla_paths
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Joomla.Fieldtype.Config')->approved_joomla_paths
|
||||
);
|
||||
}
|
||||
|
||||
@@ -133,7 +126,7 @@ class Fieldtype implements ServiceProviderInterface
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return RemoteConfig
|
||||
* @since 5.2.1
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getRemoteConfig(Container $container): RemoteConfig
|
||||
{
|
||||
@@ -155,7 +148,9 @@ class Fieldtype implements ServiceProviderInterface
|
||||
return new Get(
|
||||
$container->get('Joomla.Fieldtype.Remote.Config'),
|
||||
$container->get('Joomla.Fieldtype.Grep'),
|
||||
$container->get('Data.Item')
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -175,9 +170,10 @@ class Fieldtype implements ServiceProviderInterface
|
||||
$container->get('Data.Items'),
|
||||
$container->get('Joomla.Fieldtype.Readme.Item'),
|
||||
$container->get('Joomla.Fieldtype.Readme.Main'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message'),
|
||||
$container->get('Config')->approved_joomla_paths
|
||||
$container->get('Joomla.Fieldtype.Config')->approved_joomla_paths
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,148 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2020
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\File;
|
||||
|
||||
|
||||
use Joomla\CMS\Image\Image as JoomlaImage;
|
||||
use Joomla\CMS\Log\Log;
|
||||
use Joomla\Filesystem\File;
|
||||
use Joomla\Filesystem\Folder;
|
||||
use VDM\Joomla\Utilities\MimeHelper;
|
||||
|
||||
|
||||
/**
|
||||
* Image Class
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Image
|
||||
{
|
||||
/**
|
||||
* Process one image into multiple dimensioned versions.
|
||||
*
|
||||
* @param string $source Full path to source image.
|
||||
* @param string $destinationDir Destination folder (will be created if missing).
|
||||
* @param array $dimensions Format: [['name' => 'thumb.jpg', 'width' => 100, 'height' => 100], ...]
|
||||
*
|
||||
* @return array Result array: ['thumb.jpg' => [...metadata...], 'invalid.jpg' => null, ...]
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function process(string $source, string $destinationDir, array $dimensions): array
|
||||
{
|
||||
$results = [];
|
||||
|
||||
foreach ($dimensions as $set)
|
||||
{
|
||||
if (
|
||||
!isset($set['name'], $set['width'], $set['height']) ||
|
||||
!is_numeric($set['width']) ||
|
||||
!is_numeric($set['height'])
|
||||
)
|
||||
{
|
||||
$results[$set['name'] ?? 'unknown'] = null;
|
||||
continue;
|
||||
}
|
||||
|
||||
$outputPath = rtrim($destinationDir, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR . $set['name'];
|
||||
$results[$set['name']] = $this->cropResize($source, $outputPath, (int) $set['width'], (int) $set['height']);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Crop or scale an image to target size using center crop or just resize if aspect ratio matches.
|
||||
*
|
||||
* @param string $source Full absolute path to source image.
|
||||
* @param string $destination Full absolute path to destination image.
|
||||
* @param int $targetW Target width
|
||||
* @param int $targetH Target height
|
||||
*
|
||||
* @return array|null Image metadata on success, false on failure.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function cropResize(string $source, string $destination, int $targetW, int $targetH): ?array
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!is_file($source))
|
||||
{
|
||||
throw new \RuntimeException("Source image not found: $source");
|
||||
}
|
||||
|
||||
$destFolder = dirname($destination);
|
||||
if (!is_dir($destFolder))
|
||||
{
|
||||
Folder::create($destFolder);
|
||||
}
|
||||
|
||||
$image = new JoomlaImage($source);
|
||||
|
||||
if (!$image->isLoaded())
|
||||
{
|
||||
throw new \RuntimeException("Failed to load image: $source");
|
||||
}
|
||||
|
||||
$originalW = $image->getWidth();
|
||||
$originalH = $image->getHeight();
|
||||
|
||||
// If already correct size, copy directly
|
||||
if ($originalW === $targetW && $originalH === $targetH)
|
||||
{
|
||||
File::copy($source, $destination);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Perform crop-resize directly
|
||||
$image = $image->cropResize($targetW, $targetH, true);
|
||||
$type = $this->getImageType($source);
|
||||
|
||||
if ($type === null || !$image->toFile($destination, $type))
|
||||
{
|
||||
throw new \RuntimeException("Failed to save image to $destination");
|
||||
}
|
||||
}
|
||||
|
||||
// Return metadata
|
||||
return [
|
||||
'name' => basename($destination),
|
||||
'extension' => MimeHelper::Extension($destination),
|
||||
'size' => is_file($destination) ? filesize($destination) : 0,
|
||||
'mime' => MimeHelper::MimeType($destination),
|
||||
'path' => $destination,
|
||||
];
|
||||
}
|
||||
catch (\Throwable $e)
|
||||
{
|
||||
Log::add($e->getMessage(), Log::ERROR, 'image-cropper');
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the image type constant from the file path
|
||||
*
|
||||
* @param string $path Absolute path to the image file
|
||||
*
|
||||
* @return int|null Returns the IMAGETYPE_* constant or null if undetectable
|
||||
* @since 5.1.1
|
||||
*/
|
||||
private static function getImageType(string $path): ?int
|
||||
{
|
||||
// Use exif_imagetype to get the constant
|
||||
$type = @exif_imagetype($path);
|
||||
|
||||
// Validate it's a known IMAGETYPE
|
||||
return is_int($type) ? $type : null;
|
||||
}
|
||||
}
|
||||
|
@@ -21,6 +21,7 @@ use VDM\Joomla\Interfaces\Data\ItemsInterface as Items;
|
||||
use VDM\Joomla\Data\Guid;
|
||||
use VDM\Joomla\Componentbuilder\File\Type;
|
||||
use VDM\Joomla\Componentbuilder\File\Handler;
|
||||
use VDM\Joomla\Componentbuilder\File\Image;
|
||||
use VDM\Joomla\Utilities\MimeHelper;
|
||||
|
||||
|
||||
@@ -29,7 +30,7 @@ use VDM\Joomla\Utilities\MimeHelper;
|
||||
*
|
||||
* @since 5.0.2
|
||||
*/
|
||||
final class Manager
|
||||
class Manager
|
||||
{
|
||||
/**
|
||||
* The Globally Unique Identifier.
|
||||
@@ -70,6 +71,14 @@ final class Manager
|
||||
*/
|
||||
protected Handler $handler;
|
||||
|
||||
/**
|
||||
* The Image Class.
|
||||
*
|
||||
* @var Image
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Image $image;
|
||||
|
||||
/**
|
||||
* The active user
|
||||
*
|
||||
@@ -93,15 +102,18 @@ final class Manager
|
||||
* @param Items $items The Items Class.
|
||||
* @param Type $type The Type Class.
|
||||
* @param Handler $handler The Handler Class.
|
||||
* @param Image $image The Image Class.
|
||||
*
|
||||
* @since 5.0.2
|
||||
*/
|
||||
public function __construct(Item $item, Items $items, Type $type, Handler $handler)
|
||||
public function __construct(Item $item, Items $items, Type $type, Handler $handler,
|
||||
Image $image)
|
||||
{
|
||||
$this->item = $item;
|
||||
$this->items = $items;
|
||||
$this->type = $type;
|
||||
$this->handler = $handler;
|
||||
$this->image = $image;
|
||||
$this->user = Factory::getApplication()->getIdentity();
|
||||
}
|
||||
|
||||
@@ -146,10 +158,10 @@ final class Manager
|
||||
throw new \RuntimeException($this->handler->getErrors());
|
||||
}
|
||||
|
||||
// we might need to crop images
|
||||
if ($fileType['type'] === 'image')
|
||||
{
|
||||
// $this->cropImage($details, $guid);
|
||||
$this->processImages($details, $guid, $entity, $target, $fileType);
|
||||
return;
|
||||
}
|
||||
|
||||
// store file in the file table
|
||||
@@ -225,6 +237,72 @@ final class Manager
|
||||
return $this->table;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the image(s) as needed based on crop settings
|
||||
*
|
||||
* @param array $details The uploaded file details.
|
||||
* @param string $guid The file type guid
|
||||
* @param string $entity The entity guid
|
||||
* @param string $target The target entity name
|
||||
* @param array $fileType The file type
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function processImages(array $details, string $guid, string $entity, string $target, array $fileType): void
|
||||
{
|
||||
if (empty($fileType['crop']))
|
||||
{
|
||||
// store file in the file table
|
||||
$this->item->table($this->getTable())->set(
|
||||
$this->modelFileDetails($details, $guid, $entity, $target, $fileType)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
$source = $details['full_path'];
|
||||
$path = $details['path'];
|
||||
$cropping = $fileType['crop'];
|
||||
|
||||
$placeholders = [
|
||||
'{number}' => $this->getFileNumber($fileType, $entity),
|
||||
'{name}' => $this->getFileName($details, $entity),
|
||||
'{extension}' => $this->getFileExtension($source)
|
||||
];
|
||||
|
||||
foreach ($cropping as &$crop)
|
||||
{
|
||||
$crop['name'] = str_replace(array_keys($placeholders), array_values($placeholders), $crop['name']);
|
||||
}
|
||||
|
||||
$images = $this->image->process($source, $path, $cropping);
|
||||
|
||||
foreach($images as $image)
|
||||
{
|
||||
if (empty($image))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$details['name'] = $image['name'];
|
||||
$details['extension'] = $image['extension'];
|
||||
$details['size'] = $image['size'];
|
||||
$details['mime'] = $image['mime'];
|
||||
$details['full_path'] = $image['path'];
|
||||
|
||||
// store file in the file table
|
||||
$this->item->table($this->getTable())->set(
|
||||
$this->modelFileDetails($details, $guid, $entity, $target, $fileType)
|
||||
);
|
||||
}
|
||||
|
||||
// clean up source image
|
||||
if (is_file($source) && is_writable($source))
|
||||
{
|
||||
File::delete($source); // from file system
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* model the file details to store in the file table
|
||||
*
|
||||
@@ -252,6 +330,89 @@ final class Manager
|
||||
'guid' => $this->getGuid('guid'),
|
||||
'created_by' => $this->user->id
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file name without extension for download.
|
||||
*
|
||||
* If the original name is empty, return the entity GUID.
|
||||
* If the name does not contain a '.', return the name as is.
|
||||
* Otherwise, return the name without the final extension.
|
||||
*
|
||||
* @param array $details The uploaded file details.
|
||||
* @param string $entity The entity GUID used as fallback.
|
||||
*
|
||||
* @return string The extracted or fallback file name.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getFileName(array $details, string $entity): string
|
||||
{
|
||||
// Check if name is set and non-empty
|
||||
$name = trim($details['name'] ?? '');
|
||||
|
||||
// Return entity if name is empty
|
||||
if ($name === '')
|
||||
{
|
||||
return $entity;
|
||||
}
|
||||
|
||||
// If there is no dot in the name, assume no extension — return as-is
|
||||
if (strpos($name, '.') === false)
|
||||
{
|
||||
return $name;
|
||||
}
|
||||
|
||||
// Use pathinfo to extract the name without extension
|
||||
$info = pathinfo($name);
|
||||
|
||||
// Return filename (without extension)
|
||||
return $info['filename'] ?? $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file number TODO: not ideal, if images are deleted we need a better solution
|
||||
*
|
||||
* @param array $fileType The uploaded file type details.
|
||||
* @param string $entity The entity guid
|
||||
*
|
||||
* @return int
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getFileNumber(array $fileType, string $entity): int
|
||||
{
|
||||
if (empty($fileType['crop']))
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
$number = count($fileType['crop']);
|
||||
$number_files = 1;
|
||||
|
||||
if (($files = $this->items->table($this->getTable())->values([$entity], 'entity')) !== null)
|
||||
{
|
||||
$total = count($files);
|
||||
if ($total >= $number)
|
||||
{
|
||||
$number_files = round($total / $number);
|
||||
}
|
||||
|
||||
return ++$number_files;
|
||||
}
|
||||
|
||||
return $number_files;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the file extension
|
||||
*
|
||||
* @param sring $source The full path to the file
|
||||
*
|
||||
* @return string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getFileExtension(string $source): string
|
||||
{
|
||||
return MimeHelper::extension($source);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -18,6 +18,7 @@ use VDM\Joomla\Componentbuilder\File\Type;
|
||||
use VDM\Joomla\Componentbuilder\File\Handler;
|
||||
use VDM\Joomla\Componentbuilder\File\Manager;
|
||||
use VDM\Joomla\Componentbuilder\File\Display;
|
||||
use VDM\Joomla\Componentbuilder\File\Image;
|
||||
|
||||
|
||||
/**
|
||||
@@ -48,6 +49,9 @@ class File implements ServiceProviderInterface
|
||||
|
||||
$container->alias(Display::class, 'File.Display')
|
||||
->share('File.Display', [$this, 'getDisplay'], true);
|
||||
|
||||
$container->alias(Image::class, 'File.Image')
|
||||
->share('File.Image', [$this, 'getImage'], true);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -92,7 +96,8 @@ class File implements ServiceProviderInterface
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Data.Items'),
|
||||
$container->get('File.Type'),
|
||||
$container->get('File.Handler')
|
||||
$container->get('File.Handler'),
|
||||
$container->get('File.Image')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -110,6 +115,19 @@ class File implements ServiceProviderInterface
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Data.Items')
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Image Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Image
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getImage(Container $container): Image
|
||||
{
|
||||
return new Image();
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -100,7 +100,8 @@ final class Type
|
||||
'type' => $this->getFieldName($fileType),
|
||||
'formats' => $this->getAllowFormats($fileType) ?? [],
|
||||
'filter' => $fileType->filter ?? null,
|
||||
'path' => $this->getFileTypePath($fileType)
|
||||
'path' => $this->getFileTypePath($fileType),
|
||||
'crop' => $this->getCropDetails($fileType)
|
||||
];
|
||||
}
|
||||
|
||||
@@ -159,6 +160,30 @@ final class Type
|
||||
return 'file';
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the image crop details if set.
|
||||
*
|
||||
* Ensures the returned structure is always an array of arrays,
|
||||
* converting any stdClass to array recursively.
|
||||
*
|
||||
* @param object $data The type data object.
|
||||
*
|
||||
* @return array The image crop details.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getCropDetails(object $data): array
|
||||
{
|
||||
if (($data->type ?? 0) !== 1 || empty($data->crop))
|
||||
{
|
||||
return [];
|
||||
}
|
||||
|
||||
// Use native JSON method to deeply convert stdClass → array
|
||||
$crop = json_decode(json_encode($data->crop), true) ?? [];
|
||||
|
||||
return array_values($crop);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the allow formats (for script)
|
||||
*
|
||||
|
@@ -53,7 +53,7 @@ final class Item implements ImportItemInterface
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Validator $validator The Table ValidatorI Class.
|
||||
* @param Validator $validator The Table Validator Class.
|
||||
* @param DataItem $item The Item Class.
|
||||
* @param Row $row The Import Row Class.
|
||||
*
|
||||
|
@@ -13,10 +13,14 @@ namespace VDM\Joomla\Componentbuilder\JoomlaPower;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use VDM\Joomla\Componentbuilder\JoomlaPower\Service\JoomlaPower as Power;
|
||||
use VDM\Joomla\Componentbuilder\JoomlaPower\Service\JoomlaPower;
|
||||
use VDM\Joomla\Componentbuilder\Package\Service\Power;
|
||||
use VDM\Joomla\Service\Database;
|
||||
use VDM\Joomla\Service\Model;
|
||||
use VDM\Joomla\Service\Data;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Git;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Github;
|
||||
use VDM\Joomla\Github\Service\Utilities as GithubUtilities;
|
||||
use VDM\Joomla\Componentbuilder\Service\Gitea;
|
||||
use VDM\Joomla\Componentbuilder\Power\Service\Gitea as GiteaPower;
|
||||
use VDM\Joomla\Gitea\Service\Utilities as GiteaUtilities;
|
||||
@@ -51,10 +55,14 @@ abstract class Factory extends ExtendingFactory implements FactoryInterface
|
||||
protected static function createContainer(): Container
|
||||
{
|
||||
return (new Container())
|
||||
->registerServiceProvider(new JoomlaPower())
|
||||
->registerServiceProvider(new Power())
|
||||
->registerServiceProvider(new Database())
|
||||
->registerServiceProvider(new Model())
|
||||
->registerServiceProvider(new Data())
|
||||
->registerServiceProvider(new Git())
|
||||
->registerServiceProvider(new Github())
|
||||
->registerServiceProvider(new GithubUtilities())
|
||||
->registerServiceProvider(new Gitea())
|
||||
->registerServiceProvider(new GiteaPower())
|
||||
->registerServiceProvider(new GiteaUtilities())
|
||||
|
@@ -65,78 +65,66 @@ final class Grep extends ExtendingGrep implements GrepInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a remote joomla power
|
||||
* Get a remote joomla power object from a repository.
|
||||
*
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique id of the power
|
||||
* @param object $path The repository path details
|
||||
* @param string $guid The global unique ID of the power
|
||||
*
|
||||
* @return object|null
|
||||
* @since 3.2.0
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getRemote(object $path, string $guid): ?object
|
||||
{
|
||||
$power = null;
|
||||
if (empty($path->index->{$guid}->path))
|
||||
$relative_path = $path->index[$this->entity]->{$guid}->path ?? null;
|
||||
if (empty($relative_path))
|
||||
{
|
||||
return $power;
|
||||
return null;
|
||||
}
|
||||
|
||||
// get the branch name
|
||||
$branch = $this->getBranchName($path);
|
||||
$branch = $this->getBranchName($path);
|
||||
$guid_field = $this->getGuidField();
|
||||
$settings_name = $this->getSettingsName();
|
||||
$readme_enabled = $this->hasItemReadme();
|
||||
|
||||
// get the guid_field key
|
||||
$guid_field = $this->getGuidField();
|
||||
|
||||
// get the settings path
|
||||
$settings_path = $this->getSettingsPath();
|
||||
// set the target system
|
||||
$target = $path->target ?? 'gitea';
|
||||
$this->contents->setTarget($target);
|
||||
|
||||
// load the base and token if set
|
||||
$this->loadApi($this->contents, $path->base ?? null, $path->token ?? null);
|
||||
$this->loadApi(
|
||||
$this->contents,
|
||||
$target === 'gitea' ? ($path->base ?? null) : null,
|
||||
$path->token ?? null
|
||||
);
|
||||
|
||||
// get the settings
|
||||
if (($power = $this->loadRemoteFile($path->organisation, $path->repository, $path->index->{$guid}->path . '/' . $settings_path, $branch)) !== null &&
|
||||
isset($power->{$guid_field}))
|
||||
$power = $this->loadRemoteFile(
|
||||
$path->organisation,
|
||||
$path->repository,
|
||||
"{$relative_path}/{$settings_name}",
|
||||
$branch
|
||||
);
|
||||
|
||||
if ($power === null || !isset($power->{$guid_field}))
|
||||
{
|
||||
// set the git details in params
|
||||
$path_guid = $path->guid ?? null;
|
||||
if ($path_guid !== null)
|
||||
$this->contents->reset_();
|
||||
return null;
|
||||
}
|
||||
|
||||
$path_guid = $path->guid ?? null;
|
||||
|
||||
$branch_field = $this->getBranchField();
|
||||
|
||||
if ($branch_field === 'write_branch' && $path_guid !== null)
|
||||
{
|
||||
$this->setRepoItemSha($power, $path, "{$relative_path}/{$settings_name}", $branch, "{$path_guid}-settings");
|
||||
|
||||
if ($readme_enabled)
|
||||
{
|
||||
// get the Settings meta
|
||||
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/' . $settings_path, $branch)) !== null &&
|
||||
isset($meta->sha))
|
||||
{
|
||||
if (isset($power->params) && is_object($power->params) &&
|
||||
isset($power->params->source) && is_array($power->params->source))
|
||||
{
|
||||
$power->params->source[$path_guid . '-settings'] = $meta->sha;
|
||||
}
|
||||
else
|
||||
{
|
||||
$power->params = (object) [
|
||||
'source' => [$path_guid . '-settings' => $meta->sha]
|
||||
];
|
||||
}
|
||||
}
|
||||
// get the README meta
|
||||
if (($meta = $this->contents->metadata($path->organisation, $path->repository, $path->index->{$guid}->path . '/README.md', $branch)) !== null &&
|
||||
isset($meta->sha))
|
||||
{
|
||||
if (isset($power->params) && is_object($power->params) &&
|
||||
isset($power->params->source) && is_array($power->params->source))
|
||||
{
|
||||
$power->params->source[$path_guid . '-readme'] = $meta->sha;
|
||||
}
|
||||
else
|
||||
{
|
||||
$power->params = (object) [
|
||||
'source' => [$path_guid . '-readme' => $meta->sha]
|
||||
];
|
||||
}
|
||||
}
|
||||
$readme_name = $this->getItemReadmeName();
|
||||
$this->setRepoItemSha($power, $path, "{$relative_path}/{$readme_name}", $branch, "{$path_guid}-readme");
|
||||
}
|
||||
}
|
||||
|
||||
// reset back to the global base and token
|
||||
$this->contents->reset_();
|
||||
|
||||
return $power;
|
||||
|
@@ -22,45 +22,108 @@ use VDM\Joomla\Interfaces\Readme\ItemInterface;
|
||||
final class Item implements ItemInterface
|
||||
{
|
||||
/**
|
||||
* Get an item readme
|
||||
* Generate a README for a Joomla! Power entity in Markdown format.
|
||||
*
|
||||
* @param object $item An item details.
|
||||
* This includes the system name, description, settings table, and usage instructions.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @param object $item The Joomla! Power item definition.
|
||||
*
|
||||
* @return string The generated README as Markdown.
|
||||
* @since 3.2.2
|
||||
*/
|
||||
public function get(object $item): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗ ██████╗ ██████╗ ██╗ ██╗███████╗██████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗ ██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║ ██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║ ██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║ ██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝ ╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝
|
||||
```"];
|
||||
// system name
|
||||
$readme[] = "# " . $item->system_name;
|
||||
$readme = [];
|
||||
|
||||
// Title and system name
|
||||
$readme[] = '### Joomla! Power';
|
||||
$readme[] = '# ' . ($item->system_name ?? 'error: missing system name');
|
||||
$readme[] = '';
|
||||
|
||||
// Description block
|
||||
if (!empty($item->description))
|
||||
{
|
||||
$readme[] = "\n" . $item->description;
|
||||
$readme[] = trim($item->description);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
$readme[] = "\nThe Joomla! Power feature allows you to use Joomla classes in your project without manually managing their namespaces. JCB will automatically add the correct namespaces to your files. If Joomla classes change in future versions, such as from Joomla 3 to 5, JCB will update them for you.\n\nHowever, if there are breaking changes in function names, you may need to make some manual adjustments. The Joomla Power Key (JPK) helps you easily search for these classes.\n\nBy using the JPK (Joomla Power Key) in your custom code (replacing the class name in your code with the JPK), JCB will automatically pull the Joomla! Power from the repository into your project.\n\nTo add this specific power to your project in JCB:\n\n> simply use this JPK\n```\n" . 'Joomla---' . str_replace('-', '_', $item->guid) . '---Power' . "\n```\n> remember to replace the `---` with `___` to activate this Joomla! Power in your code";
|
||||
// Settings table
|
||||
if (!empty($item->settings) && (is_array($item->settings) || is_object($item->settings)))
|
||||
{
|
||||
$readme[] = $this->buildSettingsTable($item->settings);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗██████╗
|
||||
██║██╔════╝██╔══██╗
|
||||
██║██║ ██████╔╝
|
||||
██ ██║██║ ██╔══██╗
|
||||
╚█████╔╝╚██████╗██████╔╝
|
||||
╚════╝ ╚═════╝╚═════╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
// Usage instructions
|
||||
$guid = $item->guid ?? 'error_missing_guid';
|
||||
$readme[] = '> This Joomla! Power lets you seamlessly integrate and future-proof Joomla classes in your custom code.';
|
||||
$readme[] = '';
|
||||
$readme[] = 'To add this specific power to your project in JCB:';
|
||||
$readme[] = '';
|
||||
$readme[] = 'Simply use this JPK:';
|
||||
$readme[] = '```';
|
||||
$readme[] = 'Joomla---' . str_replace('-', '_', $guid) . '---Power';
|
||||
$readme[] = '```';
|
||||
$readme[] = '> Remember to replace the `---` with `___` to activate this Joomla! Power in your code.';
|
||||
$readme[] = '';
|
||||
|
||||
// Footer
|
||||
|
||||
$readme[] = <<<MD
|
||||
### Used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
||||
/**
|
||||
* Builds a Markdown table with details about each setting.
|
||||
*
|
||||
* The table includes columns: Namespace (inline `use ...;` code style) and Joomla Version (as shield badge).
|
||||
*
|
||||
* @param array|object $settings Associative array or object containing settings.
|
||||
*
|
||||
* @return string The generated Markdown output.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function buildSettingsTable(array|object $settings): string
|
||||
{
|
||||
$settings = (array) $settings;
|
||||
$markdown = [];
|
||||
|
||||
// Table header
|
||||
$markdown[] = '| Namespace | Joomla Version |';
|
||||
$markdown[] = '|-----------|----------------|';
|
||||
|
||||
foreach ($settings as $setting)
|
||||
{
|
||||
$setting = (array) $setting;
|
||||
|
||||
// Inline namespace string as `use Namespace\Class;`
|
||||
$namespace = isset($setting['namespace'])
|
||||
? '`use ' . $setting['namespace'] . ';`'
|
||||
: '`—`';
|
||||
|
||||
// Map version to badge label
|
||||
$versionMap = [
|
||||
'0' => ['All', 'purple'],
|
||||
'3' => ['Joomla 3', 'blue'],
|
||||
'4' => ['Joomla 4', 'green'],
|
||||
'5' => ['Joomla 5', 'brightgreen']
|
||||
];
|
||||
|
||||
$versionCode = (string) ($setting['joomla_version'] ?? '0');
|
||||
[$label, $color] = $versionMap[$versionCode] ?? ['Unknown', 'lightgrey'];
|
||||
|
||||
$versionBadge = "";
|
||||
|
||||
$markdown[] = "| {$namespace} | {$versionBadge} |";
|
||||
}
|
||||
|
||||
return implode("\n", $markdown);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -16,69 +16,87 @@ use VDM\Joomla\Interfaces\Readme\MainInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Compiler Power Main Readme
|
||||
* Compiler Joomla Power Main Readme
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
final class Main implements MainInterface
|
||||
{
|
||||
/**
|
||||
* Get Main Readme
|
||||
* Generate the main README for the JCB Joomla Powers repository in Markdown format.
|
||||
*
|
||||
* @param array $items All items of this repository.
|
||||
* This README explains the purpose and function of Joomla Powers (JPKs), including dynamic class resolution,
|
||||
* namespace management, and automatic `use` statement injection. It also lists all powers in this repository.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
* @param array $items All items (Joomla Powers) assigned to this repository.
|
||||
*
|
||||
* @return string The full generated Markdown README.
|
||||
* @since 3.2.0
|
||||
*/
|
||||
public function get(array $items): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
██████╗ ██████╗ ██╗ ██╗███████╗██████╗ ███████╗
|
||||
██╔══██╗██╔═══██╗██║ ██║██╔════╝██╔══██╗██╔════╝
|
||||
██████╔╝██║ ██║██║ █╗ ██║█████╗ ██████╔╝███████╗
|
||||
██╔═══╝ ██║ ██║██║███╗██║██╔══╝ ██╔══██╗╚════██║
|
||||
██║ ╚██████╔╝╚███╔███╔╝███████╗██║ ██║███████║
|
||||
╚═╝ ╚═════╝ ╚══╝╚══╝ ╚══════╝╚═╝ ╚═╝╚══════╝
|
||||
```"];
|
||||
$readme = [];
|
||||
|
||||
// default description of super powers
|
||||
$readme[] = "\n### What is JCB Joomla Powers?\nThe Joomla Component Builder (JCB) Joomla Power features are designed to enhance JCB's functionality and streamline the development process. The Joomla powers enable developers to effectively leverage Joomla classes in their custom code without needing to manually add the `use` statements for those classes to the file headers. JCB automatically updates these `use` statements in the necessary headers when it detects a Joomla power key in the custom code.\n
|
||||
\n
|
||||
By doing this, we can control the `use` statements dynamically from a central point. This is particularly beneficial when transitioning from Joomla 3 to Joomla 4, as it allows us to seamlessly switch from certain classes to their respective Joomla framework classes and vice versa. Maintaining these `use` statements in the Joomla Power area ensures that JCB handles the inclusion and updating of class names to prevent conflicts with other classes.\n
|
||||
\n
|
||||
This approach is convenient and allows developers to focus on the bespoke parts of their application logic without worrying about class declarations.\n
|
||||
\nThis repository contains an index (see below) of all the Joomla! Powers within the JCB core GUI. These Joomla! Powers are automatically added to the repository by our maintainers, ensuring a well-organized and accessible collection of Joomla Classes are maintained.\n";
|
||||
// Header
|
||||
$readme[] = '# Joomla! Power';
|
||||
$readme[] = '';
|
||||
|
||||
// get the readme body
|
||||
// Description
|
||||
$readme[] = '### What Are Joomla Powers in JCB?';
|
||||
$readme[] = <<<MD
|
||||
Joomla Powers in JCB are a smart way to include Joomla classes in your custom code — **without hardcoding their full class names or import paths**.
|
||||
|
||||
Instead of writing `\\Joomla\\CMS\\Factory::getApplication()->enqueueMessage(...);` manually, you can simply place a **Joomla Power Key (JPK)** in your code, like this:
|
||||
|
||||
```
|
||||
Joomla---39403062_84fb_46e0_bac4_0023f766e827---Power::getApplication()->enqueueMessage(...);
|
||||
```
|
||||
|
||||
> Replace each `---` with `___` when using the key inside your code.
|
||||
|
||||
JCB will automatically:
|
||||
|
||||
- Resolve this JPK to the correct class path for your current Joomla version.
|
||||
- Add the correct `use` statement to the top of the file.
|
||||
- Detect and resolve naming collisions by automatically generating an `as` alias (e.g., `use Joomla\CMS\Factory as CMSFactory;`).
|
||||
- Replace the JPK in your code with the correct class name (either the original or aliased name).
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// Why explanation
|
||||
$readme[] = '### Why This Matters';
|
||||
$readme[] = <<<MD
|
||||
Joomla occasionally moves classes between namespaces (e.g., from `Joomla\CMS\` to `Joomla\Framework\`).
|
||||
|
||||
By using JPKs, you no longer need to manually update class paths when switching between Joomla 3, 4, or 5+.
|
||||
**Your code becomes version-independent** — JCB handles the class namespacing and **use statement** injection during compilation.
|
||||
|
||||
You write clean, readable logic — and JCB ensures compatibility under the hood.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// What can be found here
|
||||
$readme[] = '### What's in This Repository?';
|
||||
$readme[] = <<<MD
|
||||
This repository contains a **index of Joomla Powers** to be used in a JCB instance.
|
||||
|
||||
The list below shows all Joomla Powers available in this repository — each one usable via its unique JPK.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// Dynamic list of joomla powers
|
||||
$readme[] = $this->readmeBuilder($items);
|
||||
$readme[] = '';
|
||||
|
||||
$readme[] = <<<MD
|
||||
### All used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗ ███╗ ██╗███████╗███╗ ██╗████████╗
|
||||
██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗████╗ ██║██╔════╝████╗ ██║╚══██╔══╝
|
||||
██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║██╔██╗ ██║█████╗ ██╔██╗ ██║ ██║
|
||||
██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║ ██║██║╚██╗██║██╔══╝ ██║╚██╗██║ ██║
|
||||
╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚██████╔╝██║ ╚████║███████╗██║ ╚████║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═══╝ ╚═╝
|
||||
██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗
|
||||
██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗
|
||||
██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝
|
||||
██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗
|
||||
██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
@@ -53,7 +53,7 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
// [DEFAULT] protected string $suffix_key = '---Power';
|
||||
protected string $suffix_key = '---Power';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
@@ -63,6 +63,14 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
*/
|
||||
// [DEFAULT] protected string $main_readme_path = 'README.md';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
// [DEFAULT] protected string $item_readme_name = 'README.md';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
@@ -80,12 +88,12 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
// [DEFAULT] protected string $src_path = 'src';
|
||||
|
||||
/**
|
||||
* The item settings file path
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
// [DEFAULT] protected string $settings_path = 'item.json';
|
||||
// [DEFAULT] protected string $settings_name = 'item.json';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
@@ -143,12 +151,7 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
protected array $placeholders = [
|
||||
'[['.'[NamespacePrefix]]]' => 'VDM',
|
||||
'[['.'[ComponentNamespace]]]' => 'Componentbuilder',
|
||||
'[['.'[Component]]]' => 'Componentbuilder',
|
||||
'[['.'[component]]]' => 'componentbuilder'
|
||||
];
|
||||
protected array $placeholders = [];
|
||||
[DEFAULT] */
|
||||
}
|
||||
|
||||
|
@@ -53,9 +53,11 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexSettingsPath($item), // The file path.
|
||||
json_encode($item, JSON_PRETTY_PRINT), // The file content.
|
||||
'Update ' . $item->system_name, // The commit message.
|
||||
'Update ' . $item_name, // The commit message.
|
||||
$sha, // The blob SHA of the old file.
|
||||
$repo->write_branch // The branch name.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
|
||||
$success = is_object($result);
|
||||
@@ -84,8 +86,10 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexSettingsPath($item), // The file path.
|
||||
json_encode($item, JSON_PRETTY_PRINT), // The file content.
|
||||
'Create ' . $item->system_name, // The commit message.
|
||||
$repo->write_branch // The branch name.
|
||||
'Create ' . $this->index_map_IndexName($item), // The commit message.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
|
||||
return is_object($result);
|
||||
@@ -113,11 +117,13 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$this->git->update(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexPath($item) . '/README.md', // The file path.
|
||||
$this->index_map_IndexReadmePath($item), // The file path.
|
||||
$this->itemReadme->get($item), // The file content.
|
||||
'Update ' . $item->system_name . ' readme file', // The commit message.
|
||||
'Update ' . $this->index_map_IndexName($item) . ' readme file', // The commit message.
|
||||
$sha, // The blob SHA of the old file.
|
||||
$repo->write_branch // The branch name.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
}
|
||||
|
||||
@@ -135,10 +141,12 @@ final class Set extends ExtendingSet implements SetInterface
|
||||
$this->git->create(
|
||||
$repo->organisation, // The owner name.
|
||||
$repo->repository, // The repository name.
|
||||
$this->index_map_IndexPath($item) . '/README.md', // The file path.
|
||||
$this->index_map_IndexReadmePath($item), // The file path.
|
||||
$this->itemReadme->get($item), // The file content.
|
||||
'Create ' . $item->system_name . ' readme file', // The commit message.
|
||||
$repo->write_branch // The branch name.
|
||||
'Create ' . $this->index_map_IndexName($item) . ' readme file', // The commit message.
|
||||
$repo->write_branch, // The branch name.
|
||||
$repo->author_name, // The author name.
|
||||
$repo->author_email // The author email.
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@@ -15,8 +15,6 @@ namespace VDM\Joomla\Componentbuilder\JoomlaPower\Service;
|
||||
use Joomla\DI\Container;
|
||||
use Joomla\DI\ServiceProviderInterface;
|
||||
use VDM\Joomla\Componentbuilder\JoomlaPower\Config;
|
||||
use VDM\Joomla\Componentbuilder\Power\Table;
|
||||
use VDM\Joomla\Componentbuilder\Package\MessageBus;
|
||||
use VDM\Joomla\Componentbuilder\JoomlaPower\Grep;
|
||||
use VDM\Joomla\Componentbuilder\JoomlaPower\Remote\Config as RemoteConfig;
|
||||
use VDM\Joomla\Componentbuilder\Power\Remote\Get;
|
||||
@@ -42,14 +40,8 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
*/
|
||||
public function register(Container $container)
|
||||
{
|
||||
$container->alias(Config::class, 'Config')
|
||||
->share('Config', [$this, 'getConfig'], true);
|
||||
|
||||
$container->alias(Table::class, 'Power.Table')->alias('Table', 'Power.Table')
|
||||
->share('Power.Table', [$this, 'getPowerTable'], true);
|
||||
|
||||
$container->alias(MessageBus::class, 'Power.Message')
|
||||
->share('Power.Message', [$this, 'getMessageBus'], true);
|
||||
$container->alias(Config::class, 'Joomla.Power.Config')->alias('Config', 'Joomla.Power.Config')
|
||||
->share('Joomla.Power.Config', [$this, 'getConfig'], true);
|
||||
|
||||
$container->alias(Grep::class, 'Joomla.Power.Grep')
|
||||
->share('Joomla.Power.Grep', [$this, 'getGrep'], true);
|
||||
@@ -83,32 +75,6 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
return new Config();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Power Table Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return Table
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function getPowerTable(Container $container): Table
|
||||
{
|
||||
return new Table();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Message Bus Class.
|
||||
*
|
||||
* @param Container $container The DI container.
|
||||
*
|
||||
* @return MessageBus
|
||||
* @since 5.2.1
|
||||
*/
|
||||
public function getMessageBus(Container $container): MessageBus
|
||||
{
|
||||
return new MessageBus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get The Grep Class.
|
||||
*
|
||||
@@ -121,9 +87,10 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
{
|
||||
return new Grep(
|
||||
$container->get('Joomla.Power.Remote.Config'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Network.Resolve'),
|
||||
$container->get('Config')->approved_joomla_paths
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Joomla.Power.Config')->approved_joomla_paths
|
||||
);
|
||||
}
|
||||
|
||||
@@ -155,7 +122,9 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
return new Get(
|
||||
$container->get('Joomla.Power.Remote.Config'),
|
||||
$container->get('Joomla.Power.Grep'),
|
||||
$container->get('Data.Item')
|
||||
$container->get('Data.Item'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message')
|
||||
);
|
||||
}
|
||||
|
||||
@@ -175,9 +144,10 @@ class JoomlaPower implements ServiceProviderInterface
|
||||
$container->get('Data.Items'),
|
||||
$container->get('Joomla.Power.Readme.Item'),
|
||||
$container->get('Joomla.Power.Readme.Main'),
|
||||
$container->get('Gitea.Repository.Contents'),
|
||||
$container->get('Git.Repository.Contents'),
|
||||
$container->get('Power.Tracker'),
|
||||
$container->get('Power.Message'),
|
||||
$container->get('Config')->approved_joomla_paths
|
||||
$container->get('Joomla.Power.Config')->approved_joomla_paths
|
||||
);
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\AdminCustomTabs\Remote;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Config as ExtendingConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Base Configure values for the remote classes
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Config extends ExtendingConfig implements ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected string $table = 'admin_custom_tabs';
|
||||
|
||||
/**
|
||||
* Area Name
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected ?string $area = 'Admin Custom Tabs';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = '';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $item_readme_name = '';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $index_path = 'index/admin-custom-tabs.json';
|
||||
|
||||
/**
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $settings_name = 'admin-custom-tabs.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $src_path = 'src/admin_view/children';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $guid_field = 'admin_view';
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\AdminFields\Remote;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Config as ExtendingConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Base Configure values for the remote classes
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Config extends ExtendingConfig implements ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected string $table = 'admin_fields';
|
||||
|
||||
/**
|
||||
* Area Name
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected ?string $area = 'Admin Fields';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = '';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $item_readme_name = '';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $index_path = 'index/admin-fields.json';
|
||||
|
||||
/**
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $settings_name = 'admin-fields.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $src_path = 'src/admin_view/children';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $guid_field = 'admin_view';
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\AdminFieldsConditions\Remote;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Config as ExtendingConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Base Configure values for the remote classes
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Config extends ExtendingConfig implements ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected string $table = 'admin_fields_conditions';
|
||||
|
||||
/**
|
||||
* Area Name
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected ?string $area = 'Admin Fields Conditions';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = '';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $item_readme_name = '';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $index_path = 'index/admin-fields-conditions.json';
|
||||
|
||||
/**
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $settings_name = 'admin-fields-conditions.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $src_path = 'src/admin_view/children';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $guid_field = 'admin_view';
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -0,0 +1,90 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\AdminFieldsRelations\Remote;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Remote\ConfigInterface;
|
||||
use VDM\Joomla\Abstraction\Remote\Config as ExtendingConfig;
|
||||
|
||||
|
||||
/**
|
||||
* Base Configure values for the remote classes
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Config extends ExtendingConfig implements ConfigInterface
|
||||
{
|
||||
/**
|
||||
* Table Name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected string $table = 'admin_fields_relations';
|
||||
|
||||
/**
|
||||
* Area Name
|
||||
*
|
||||
* @var string|null
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected ?string $area = 'Admin Fields Relations';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = '';
|
||||
|
||||
/**
|
||||
* The item readme file name
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $item_readme_name = '';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $index_path = 'index/admin-fields-relations.json';
|
||||
|
||||
/**
|
||||
* The item settings file name (item data)
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $settings_name = 'admin-fields-relations.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $src_path = 'src/admin_view/children';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $guid_field = 'admin_view';
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
@@ -12,6 +12,7 @@
|
||||
namespace VDM\Joomla\Componentbuilder\Package\AdminView\Readme;
|
||||
|
||||
|
||||
use VDM\Joomla\Utilities\String\ClassfunctionHelper;
|
||||
use VDM\Joomla\Interfaces\Readme\ItemInterface;
|
||||
|
||||
|
||||
@@ -23,56 +24,55 @@ use VDM\Joomla\Interfaces\Readme\ItemInterface;
|
||||
final class Item implements ItemInterface
|
||||
{
|
||||
/**
|
||||
* Get an item readme
|
||||
* Generate a README for a JCB Admin View in Markdown format.
|
||||
*
|
||||
* @param object $item An item details.
|
||||
* Includes the system name, code-safe identifiers, optional short/long description, and usage context.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.2
|
||||
* @param object $item The Admin View definition.
|
||||
*
|
||||
* @return string The generated README.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function get(object $item): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
|
||||
█████╗ ██████╗ ███╗ ███╗██╗███╗ ██╗ ██╗ ██╗██╗███████╗██╗ ██╗
|
||||
██╔══██╗██╔══██╗████╗ ████║██║████╗ ██║ ██║ ██║██║██╔════╝██║ ██║
|
||||
███████║██║ ██║██╔████╔██║██║██╔██╗ ██║ ██║ ██║██║█████╗ ██║ █╗ ██║
|
||||
██╔══██║██║ ██║██║╚██╔╝██║██║██║╚██╗██║ ╚██╗ ██╔╝██║██╔══╝ ██║███╗██║
|
||||
██║ ██║██████╔╝██║ ╚═╝ ██║██║██║ ╚████║ ╚████╔╝ ██║███████╗╚███╔███╔╝
|
||||
╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═══╝ ╚═╝╚══════╝ ╚══╝╚══╝
|
||||
```"];
|
||||
// system name
|
||||
$readme[] = "# " . $item->name;
|
||||
$readme = [];
|
||||
|
||||
if (!empty($item->description))
|
||||
// Title
|
||||
$readme[] = '### JCB! Admin View';
|
||||
|
||||
$systemName = $item->system_name ?? 'error: missing system name';
|
||||
$nameSingle = $item->name_single ?? 'edit';
|
||||
$nameList = $item->name_list ?? 'list';
|
||||
$codeNames = ClassfunctionHelper::safe($nameSingle) . ':' . ClassfunctionHelper::safe($nameList);
|
||||
$readme[] = "# {$systemName} ({$codeNames})";
|
||||
$readme[] = '';
|
||||
|
||||
// Short description
|
||||
$shortDescription = $item->short_description ?? '';
|
||||
if ($shortDescription !== '' && $shortDescription !== $systemName)
|
||||
{
|
||||
$readme[] = "\n" . $item->description;
|
||||
}
|
||||
elseif (!empty($item->short_description))
|
||||
{
|
||||
$readme[] = "\n" . $item->short_description;
|
||||
$readme[] = '> ' . trim($shortDescription);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
$readme[] = "\nThe Joomla Admin View is a self‑contained backend form for a single record: it unites Fields to load existing data, validate user edits, and handle CRUD on data in the system, serving as the conduit that writes changes directly to the component’s database tables in Joomla Component Builder (JCB). By using the \"reset\" button, you can instantly synchronize this Admin View with the authoritative version hosted in our core repository, ensuring your Components always benefit from the latest refinements, performance optimizations, and security enhancements.\n\n Want something more fitting to your specific needs? Fork the repo, use the view as a blueprint and point JCB to your branch. Whether you’re layering in complex filters, interactive fields, or custom coded functionality; you stay in charge while still enjoying JCB’s effortless deployment workflow.\n
|
||||
\n
|
||||
\"This flexible approach embraces JCB’s open-source model, giving you the freedom to adapt your components to your exact needs while staying connected to a powerful and community-driven ecosystem.\"\n";
|
||||
// Full description
|
||||
$description = $item->description ?? '';
|
||||
if ($description !== '' && $description !== $shortDescription && $description !== $systemName)
|
||||
{
|
||||
$readme[] = trim($description);
|
||||
$readme[] = '';
|
||||
}
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗██████╗
|
||||
██║██╔════╝██╔══██╗
|
||||
██║██║ ██████╔╝
|
||||
██ ██║██║ ██╔══██╗
|
||||
╚█████╔╝╚██████╗██████╔╝
|
||||
╚════╝ ╚═════╝╚═════╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
// Footer
|
||||
$readme[] = '> Manage single-record forms with this reusable Admin View designed for smooth data handling, customization, and full integration in JCB.';
|
||||
$readme[] = '';
|
||||
|
||||
$readme[] = <<<MD
|
||||
### Used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
@@ -13,6 +13,7 @@ namespace VDM\Joomla\Componentbuilder\Package\AdminView\Readme;
|
||||
|
||||
|
||||
use VDM\Joomla\Interfaces\Readme\MainInterface;
|
||||
use VDM\Joomla\Componentbuilder\Package\Readme\Main as ExtendingMain;
|
||||
|
||||
|
||||
/**
|
||||
@@ -20,215 +21,98 @@ use VDM\Joomla\Interfaces\Readme\MainInterface;
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
final class Main implements MainInterface
|
||||
final class Main extends ExtendingMain implements MainInterface
|
||||
{
|
||||
/**
|
||||
* Get Main Readme
|
||||
* Generate the main README for the JCB Admin Views repository in Markdown format.
|
||||
*
|
||||
* @param array $items All items of this repository.
|
||||
* Admin Views are the backbone of JCB components — deeply tied to database tables
|
||||
* and used to generate Joomla-compliant back-end views, forms, and logic.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
* @param array $items All Admin View definitions in this repository.
|
||||
*
|
||||
* @return string The full generated Markdown README.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function get(array $items): string
|
||||
{
|
||||
// build readme
|
||||
$readme = ["```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
|
||||
█████╗ ██████╗ ███╗ ███╗██╗███╗ ██╗ ██╗ ██╗██╗███████╗██╗ ██╗███████╗
|
||||
██╔══██╗██╔══██╗████╗ ████║██║████╗ ██║ ██║ ██║██║██╔════╝██║ ██║██╔════╝
|
||||
███████║██║ ██║██╔████╔██║██║██╔██╗ ██║ ██║ ██║██║█████╗ ██║ █╗ ██║███████╗
|
||||
██╔══██║██║ ██║██║╚██╔╝██║██║██║╚██╗██║ ╚██╗ ██╔╝██║██╔══╝ ██║███╗██║╚════██║
|
||||
██║ ██║██████╔╝██║ ╚═╝ ██║██║██║ ╚████║ ╚████╔╝ ██║███████╗╚███╔███╔╝███████║
|
||||
╚═╝ ╚═╝╚═════╝ ╚═╝ ╚═╝╚═╝╚═╝ ╚═══╝ ╚═══╝ ╚═╝╚══════╝ ╚══╝╚══╝ ╚══════╝
|
||||
```"];
|
||||
$readme = [];
|
||||
|
||||
// default description of admin views
|
||||
$readme[] = "\n### What are Joomla Admin Views?\nThe Joomla admin views provide a robust interface layer that assembles backend fields, and PHP logic, enabling seamless management of component data within Joomla Component Builder (JCB). Acting as the central hub for listing, editing, and persisting records, these views standardize how components interact with the database and ensure administrators enjoy a consistent, intuitive control panel across the entire JCB ecosystem.\n
|
||||
\n
|
||||
Whenever you need to update Admin Views in any JCB project, simply select the desired views and click the \"reset\" button. The selected views is synchronized with the original version stored in this repository, bringing the latest design tweaks, security fixes, and performance boosts.\n
|
||||
\n
|
||||
If your project calls for more distinctive Admin View, or component‑specific business logic. Simply fork the repository and point JCB to your copy. This lets you maintain and evolve Admin Views independently of the main JCB community while preserving the convenience of JCB’s one‑click update mechanism.\n
|
||||
\n
|
||||
\"We believe this approach empowers you to extend and customize JCB to fit your unique requirements, exemplifying the true spirit of freedom in software development. We trust you will find this capability both useful and aligned with the expectations of how open-source software should function.\"\n";
|
||||
// Main heading
|
||||
$readme[] = '# JCB! Admin Views';
|
||||
$readme[] = '';
|
||||
|
||||
// get the readme body
|
||||
$readme[] = $this->readmeBuilder($items);
|
||||
// Description
|
||||
$readme[] = '### What Are Admin Views?';
|
||||
$readme[] = <<<MD
|
||||
**Admin Views** form the foundational interface layer of every JCB-built Joomla component.
|
||||
|
||||
// yes you can remove this, but why?
|
||||
$readme[] = "\n---\n```
|
||||
██╗ ██████╗ ██████╗ ███╗ ███╗██╗ █████╗
|
||||
██║██╔═══██╗██╔═══██╗████╗ ████║██║ ██╔══██╗
|
||||
██║██║ ██║██║ ██║██╔████╔██║██║ ███████║
|
||||
██ ██║██║ ██║██║ ██║██║╚██╔╝██║██║ ██╔══██║
|
||||
╚█████╔╝╚██████╔╝╚██████╔╝██║ ╚═╝ ██║███████╗██║ ██║
|
||||
╚════╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚══════╝╚═╝ ╚═╝
|
||||
██████╗ ██████╗ ███╗ ███╗██████╗ ██████╗ ███╗ ██╗███████╗███╗ ██╗████████╗
|
||||
██╔════╝██╔═══██╗████╗ ████║██╔══██╗██╔═══██╗████╗ ██║██╔════╝████╗ ██║╚══██╔══╝
|
||||
██║ ██║ ██║██╔████╔██║██████╔╝██║ ██║██╔██╗ ██║█████╗ ██╔██╗ ██║ ██║
|
||||
██║ ██║ ██║██║╚██╔╝██║██╔═══╝ ██║ ██║██║╚██╗██║██╔══╝ ██║╚██╗██║ ██║
|
||||
╚██████╗╚██████╔╝██║ ╚═╝ ██║██║ ╚██████╔╝██║ ╚████║███████╗██║ ╚████║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝ ╚═╝╚═╝ ╚═════╝ ╚═╝ ╚═══╝╚══════╝╚═╝ ╚═══╝ ╚═╝
|
||||
██████╗ ██╗ ██╗██╗██╗ ██████╗ ███████╗██████╗
|
||||
██╔══██╗██║ ██║██║██║ ██╔══██╗██╔════╝██╔══██╗
|
||||
██████╔╝██║ ██║██║██║ ██║ ██║█████╗ ██████╔╝
|
||||
██╔══██╗██║ ██║██║██║ ██║ ██║██╔══╝ ██╔══██╗
|
||||
██████╔╝╚██████╔╝██║███████╗██████╔╝███████╗██║ ██║
|
||||
╚═════╝ ╚═════╝ ╚═╝╚══════╝╚═════╝ ╚══════╝╚═╝ ╚═╝
|
||||
```\n> Build with [Joomla Component Builder](https://git.vdm.dev/joomla/Component-Builder)\n\n";
|
||||
Each Admin View is tightly bound to a database table and automatically generates all required:
|
||||
- **Forms**
|
||||
- **Models**
|
||||
- **Controllers**
|
||||
- **List and Edit Views**
|
||||
- **Permission handling** (ACL)
|
||||
- **Field validation and access control**
|
||||
|
||||
Admin Views are mandatory. Every JCB component must include at least one Admin View
|
||||
to be valid and compile correctly. This ensures that your component manages data
|
||||
within Joomla's native MVC architecture — offering full CRUD capabilities out-of-the-box.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// Functional Overview
|
||||
$readme[] = '### Why Are Admin Views Important?';
|
||||
$readme[] = <<<MD
|
||||
Admin Views serve as the **data anchor** for the component:
|
||||
|
||||
- Link directly to Joomla database tables
|
||||
- Automatically attach multiple fields and manage field visibility/edit permissions
|
||||
- Enable subforms (linking to other Admin Views) for nested data structures
|
||||
- Respect Joomla's ACL per view and field
|
||||
- Reusable across multiple components — compile-safe with namespace awareness
|
||||
|
||||
This makes Admin Views the heart of every component, defining its schema, edit experience,
|
||||
and administrative backbone. Unlike Custom Admin Views or Site Views (which focus more on layout or data rendering),
|
||||
Admin Views define the **structural data definition** and baseline logic.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// Sync/Fork Logic
|
||||
$readme[] = '### Versioning and Sharing';
|
||||
$readme[] = <<<MD
|
||||
When you need to update Admin Views in any JCB project:
|
||||
|
||||
- Select the views to update
|
||||
- Click **"Reset"** to pull the latest version from this repository
|
||||
- Or **Fork** this repository and point your JCB instance to your fork
|
||||
|
||||
This ensures maintainability while still allowing total customization per project.
|
||||
|
||||
>Admin Views are the schema-defining force in JCB — not just a UI pattern, but a declaration of how your component should structure and manage its data. We recommend exploring the shipped demo component to see Admin Views in action.
|
||||
|
||||
---
|
||||
MD;
|
||||
|
||||
// Index
|
||||
$readme[] = '### Index of Admin Views';
|
||||
$readme[] = '';
|
||||
|
||||
// Add the dynamic index
|
||||
$readme[] = $this->getIndex($items);
|
||||
$readme[] = '';
|
||||
|
||||
$readme[] = <<<MD
|
||||
### All used in [Joomla Component Builder](https://www.joomlacomponentbuilder.com) - [Source](https://git.vdm.dev/joomla/Component-Builder) - [Mirror](https://github.com/vdm-io/Joomla-Component-Builder) - [Download](https://git.vdm.dev/joomla/pkg-component-builder/releases)
|
||||
|
||||
---
|
||||
[](https://volunteers.joomla.org/joomlers/1396-llewellyn-van-der-merwe "Join Llewellyn on the Joomla Volunteer Portal: Shaping the Future Together!") [](https://git.vdm.dev/octoleo "--quiet") [](https://git.vdm.dev/Llewellyn "Collaborate and Innovate with Llewellyn on Git: Building a Better Code Future!") [](https://t.me/Joomla_component_builder "Join Llewellyn and the Community on Telegram: Building Joomla Components Together!") [](https://joomla.social/@llewellyn "Connect and Engage with Llewellyn on Joomla Social: Empowering Communities, One Post at a Time!") [](https://x.com/llewellynvdm "Join the Conversation with Llewellyn on X: Where Ideas Take Flight!") [](https://github.com/Llewellynvdm "Build, Innovate, and Thrive with Llewellyn on GitHub: Turning Ideas into Impact!") [](https://www.youtube.com/@OctoYou "Explore, Learn, and Create with Llewellyn on YouTube: Your Gateway to Inspiration!") [](https://n8n.io/creators/octoleo "Effortless Automation and Impactful Workflows with Llewellyn on n8n!") [](https://hub.docker.com/u/llewellyn "Llewellyn on Docker: Containerize Your Creativity!") [](https://opencollective.com/joomla-component-builder "Donate towards JCB: Help Llewellyn financially so he can continue developing this great tool!") [](https://git.vdm.dev/Llewellyn/gpg "Unlock Trust and Security with Llewellyn's GPG Key: Your Gateway to Verified Connections!")
|
||||
MD;
|
||||
|
||||
return implode("\n", $readme);
|
||||
}
|
||||
|
||||
/**
|
||||
* The readme builder
|
||||
*
|
||||
* @param array $classes The powers.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function readmeBuilder(array &$items): string
|
||||
{
|
||||
$classes = [];
|
||||
foreach ($items as $guid => $power)
|
||||
{
|
||||
// add to the sort bucket
|
||||
$classes[] = [
|
||||
'name' => $power['name'],
|
||||
'link' => $this->indexLinkPower($power)
|
||||
];
|
||||
}
|
||||
|
||||
return $this->readmeModel($classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort and model the readme classes
|
||||
*
|
||||
* @param array $classes The powers.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function readmeModel(array &$classes): string
|
||||
{
|
||||
$this->sortClasses($classes);
|
||||
|
||||
return $this->generateIndex($classes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the index string for classes
|
||||
*
|
||||
* @param array $classes The sorted classes
|
||||
*
|
||||
* @return string The index string
|
||||
*/
|
||||
private function generateIndex(array &$classes): string
|
||||
{
|
||||
$result = "# Index of Joomla! Field Types\n";
|
||||
|
||||
foreach ($classes as $class)
|
||||
{
|
||||
// Add the class details
|
||||
$result .= "\n - " . $class['link'];
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sort the flattened array using a single sorting function
|
||||
*
|
||||
* @param array $classes The classes to sort
|
||||
*
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function sortClasses(array &$classes): void
|
||||
{
|
||||
usort($classes, function ($a, $b) {
|
||||
return $this->compareName($a, $b);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Compare the name of two classes
|
||||
*
|
||||
* @param array $a First class
|
||||
* @param array $b Second class
|
||||
*
|
||||
* @return int Comparison result
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function compareName(array $a, array $b): int
|
||||
{
|
||||
return strcmp($a['name'], $b['name']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function indexLinkPower(array &$power): string
|
||||
{
|
||||
$name = $power['name'] ?? 'error';
|
||||
return '**' . $name . "** | "
|
||||
. $this->linkPowerRepo($power) . ' | '
|
||||
. $this->linkPowerSettings($power) . ' | '
|
||||
. $this->linkPowerDesc($power);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerRepo(array &$power): string
|
||||
{
|
||||
$path = $power['path'] ?? 'error';
|
||||
return '[Details](' . $path . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the Link to the power settings in this repository
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerSettings(array &$power): string
|
||||
{
|
||||
$settings = $power['settings'] ?? 'error';
|
||||
return '[Settings](' . $settings . ')';
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the short description
|
||||
*
|
||||
* @param array $power The power details.
|
||||
*
|
||||
* @return string
|
||||
* @since 3.2.0
|
||||
*/
|
||||
private function linkPowerDesc(array &$power): string
|
||||
{
|
||||
$jpk = $power['desc'] ?? '';
|
||||
return $jpk;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
@@ -39,29 +39,13 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
*/
|
||||
protected ?string $area = 'Admin View';
|
||||
|
||||
/**
|
||||
* Prefix Key
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $prefix_key = '';
|
||||
|
||||
/**
|
||||
* Suffix Key
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $suffix_key = '';
|
||||
|
||||
/**
|
||||
* The main readme file path
|
||||
*
|
||||
* @var string
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected string $main_readme_path = 'src/admin_view/README.md';
|
||||
protected string $main_readme_path = 'README_ADMIN_VIEWS.md';
|
||||
|
||||
/**
|
||||
* The index file path (index of all items)
|
||||
@@ -69,15 +53,7 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
protected string $index_path = 'admin-view-index.json';
|
||||
|
||||
/**
|
||||
* The item settings file path
|
||||
*
|
||||
* @var string
|
||||
* @since 3.2.2
|
||||
*/
|
||||
// [DEFAULT] protected string $settings_path = 'item.json';
|
||||
protected string $index_path = 'index/admin-view.json';
|
||||
|
||||
/**
|
||||
* The item (files) source path
|
||||
@@ -88,64 +64,79 @@ final class Config extends ExtendingConfig implements ConfigInterface
|
||||
protected string $src_path = 'src/admin_view';
|
||||
|
||||
/**
|
||||
* The item guid=unique field
|
||||
* The ignore fields
|
||||
*
|
||||
* @var string
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
// [DEFAULT] protected string $guid_field = 'guid';
|
||||
protected array $ignore = [
|
||||
'access',
|
||||
'addtables'
|
||||
];
|
||||
|
||||
/**
|
||||
* The item map
|
||||
* The files (to map target files to move in an entity)
|
||||
*
|
||||
* Use a pipe in the name to denote
|
||||
* subform location of the value
|
||||
* format: [field_name => path, field_name|subfrom_key => path]
|
||||
*
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $files = [
|
||||
'icon' => 'images',
|
||||
'icon_add' => 'images',
|
||||
'icon_category' => 'images'
|
||||
];
|
||||
|
||||
/**
|
||||
* The direct entities/children of this entity
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
protected array $map = [];
|
||||
[DEFAULT] */
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $children = [
|
||||
'admin_fields',
|
||||
'admin_fields_relations',
|
||||
'admin_fields_conditions',
|
||||
'admin_custom_tabs'
|
||||
];
|
||||
|
||||
/**
|
||||
* The index map
|
||||
* must always have: [name,path,guid]
|
||||
* must always have: [name,path,settings,guid]
|
||||
* you can add more
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
*/
|
||||
protected array $index_map = [
|
||||
'name' => 'index_map_IndexName',
|
||||
'path' => 'index_map_IndexPath',
|
||||
'guid' => 'index_map_IndexGUID'
|
||||
'settings' => 'index_map_IndexSettingsPath',
|
||||
'guid' => 'index_map_IndexGUID',
|
||||
'desc' => 'index_map_ShortDescription'
|
||||
];
|
||||
[DEFAULT] */
|
||||
|
||||
/**
|
||||
* The index header
|
||||
* mapping the index map to a table
|
||||
* must always have: [name,path,guid,local]
|
||||
* must always have: [name,path,settings,guid,local]
|
||||
* with [name] always first
|
||||
* with [path,guid,local] always last
|
||||
* with [path,settings,guid,local] always last
|
||||
* you can add more in between
|
||||
*
|
||||
* @var array
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $index_header = [
|
||||
'name',
|
||||
'desc',
|
||||
'path',
|
||||
'settings',
|
||||
'guid',
|
||||
'local'
|
||||
];
|
||||
[DEFAULT] */
|
||||
|
||||
/**
|
||||
* Core Placeholders
|
||||
*
|
||||
* @var array
|
||||
* @since 5.0.3
|
||||
protected array $placeholders = [
|
||||
'[['.'[NamespacePrefix]]]' => 'VDM',
|
||||
'[['.'[ComponentNamespace]]]' => 'Componentbuilder',
|
||||
'[['.'[Component]]]' => 'Componentbuilder',
|
||||
'[['.'[component]]]' => 'componentbuilder'
|
||||
];
|
||||
[DEFAULT] */
|
||||
];
|
||||
}
|
||||
|
||||
|
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\Builder;
|
||||
|
||||
|
||||
use VDM\Joomla\Abstraction\Registry;
|
||||
|
||||
|
||||
/**
|
||||
* Package Builder Entities
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Entities extends Registry
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Initializes the Registry object with optional data.
|
||||
*
|
||||
* @param mixed $data Optional data to load into the registry.
|
||||
* Can be an array, string, or object.
|
||||
* @param string|null $separator The path separator, and empty string will flatten the registry.
|
||||
* @since 5.0.4
|
||||
*/
|
||||
public function __construct($data = null, ?string $separator = null)
|
||||
{
|
||||
$entities = [
|
||||
'joomla_component' => 'Component',
|
||||
'component_admin_views' => 'ComponentAdminViews',
|
||||
'component_custom_admin_views' => 'ComponentCustomAdminViews',
|
||||
'component_site_views' => 'ComponentSiteViews',
|
||||
'component_router' => 'ComponentRouter',
|
||||
'component_config' => 'ComponentConfig',
|
||||
'component_placeholders' => 'ComponentPlaceholders',
|
||||
'component_updates' => 'ComponentUpdates',
|
||||
'component_files_folders' => 'ComponentFilesFolders',
|
||||
'component_custom_admin_menus' => 'ComponentCustomAdminMenus',
|
||||
'component_dashboard' => 'ComponentDashboard',
|
||||
'component_modules' => 'ComponentModules',
|
||||
'component_plugins' => 'ComponentPlugins',
|
||||
'joomla_module' => 'JoomlaModule',
|
||||
'joomla_module_updates' => 'JoomlaModuleUpdates',
|
||||
'joomla_module_files_folders_urls' => 'JoomlaModuleFilesFoldersUrls',
|
||||
'joomla_plugin' => 'JoomlaPlugin',
|
||||
'joomla_plugin_group' => 'JoomlaPluginGroup',
|
||||
'joomla_plugin_updates' => 'JoomlaPluginUpdates',
|
||||
'joomla_plugin_files_folders_urls' => 'JoomlaPluginFilesFoldersUrls',
|
||||
'admin_view' => 'AdminView',
|
||||
'admin_fields' => 'AdminFields',
|
||||
'admin_fields_relations' => 'AdminFieldsRelations',
|
||||
'admin_fields_conditions' => 'AdminFieldsConditions',
|
||||
'admin_custom_tabs' => 'AdminCustomTabs',
|
||||
'custom_admin_view' => 'CustomAdminView',
|
||||
'site_view' => 'SiteView',
|
||||
'template' => 'Template',
|
||||
'layout' => 'Layout',
|
||||
'dynamic_get' => 'DynamicGet',
|
||||
'custom_code' => 'CustomCode',
|
||||
'field' => 'Field',
|
||||
'library' => 'Library',
|
||||
'library_config' => 'LibraryConfig',
|
||||
'library_files_folders_urls' => 'LibraryFilesFoldersUrls',
|
||||
'class_method' => 'ClassMethod',
|
||||
'class_property' => 'ClassProperty',
|
||||
'class_extends' => 'ClassExtends',
|
||||
'placeholder' => 'Placeholder'
|
||||
];
|
||||
|
||||
parent::__construct($entities);
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,310 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\Builder;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use VDM\Joomla\Interfaces\Registryinterface as Entities;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
|
||||
|
||||
/**
|
||||
* Package Builder Get
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Get
|
||||
{
|
||||
/**
|
||||
* The Entities Class.
|
||||
*
|
||||
* @var Entities
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Entities $entities;
|
||||
|
||||
/**
|
||||
* The Tracker Class.
|
||||
*
|
||||
* @var Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Tracker $tracker;
|
||||
|
||||
/**
|
||||
* The DI Container Class.
|
||||
*
|
||||
* @var Container
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Container $container;
|
||||
|
||||
/**
|
||||
* Accumulated categorized results across recursive init calls.
|
||||
*
|
||||
* @var array<string, array<string, string>>
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected array $initResults = [
|
||||
'local' => [],
|
||||
'not_found' => [],
|
||||
'added' => [],
|
||||
];
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Entities $entities The Entities Class.
|
||||
* @param Tracker $tracker The Tracker Class.
|
||||
* @param Container $container The container Class.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(Entities $entities, Tracker $tracker, Container $container)
|
||||
{
|
||||
$this->entities = $entities;
|
||||
$this->tracker = $tracker;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes and categorizes items by checking their existence in the local database
|
||||
* and optionally retrieving them from a remote repository if not found locally.
|
||||
*
|
||||
* This method processes an array of unique identifiers (`$items`) and checks each item:
|
||||
* - If found in the local database: categorized under 'local'.
|
||||
* - If not found locally and not available remotely: categorized under 'not_found'.
|
||||
* - If retrieved from the remote repository: categorized under 'added' and stored locally.
|
||||
*
|
||||
* @param string $entity The target entity
|
||||
* @param array $items An array of item identifiers (GUIDs) to initialize and validate.
|
||||
* @param object|null $repo The repository object to search. If null, all repos will be searched.
|
||||
* @param bool $force Force a local update (if item exist locally).
|
||||
*
|
||||
* @return array{
|
||||
* local: array<string, string>,
|
||||
* not_found: array<string, string>,
|
||||
* added: array<string, string>
|
||||
* } Associative arrays indexed by GUIDs indicating the status of each item:
|
||||
* - 'local': Items already present in the local database.
|
||||
* - 'not_found': Items not found locally or remotely.
|
||||
* - 'added': Items successfully retrieved from the remote repository and stored.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function init(string $entity, array $items, ?object $repo = null, bool $force = false): array
|
||||
{
|
||||
if (($class = $this->entities->get($entity)) === null)
|
||||
{
|
||||
return $this->initResults;
|
||||
}
|
||||
|
||||
$result = $this->container->get("{$class}.Remote.Get")->init($items, $repo, $force);
|
||||
|
||||
foreach (['local', 'not_found', 'added'] as $key)
|
||||
{
|
||||
if (!empty($result[$key]))
|
||||
{
|
||||
$this->initResults[$key] += $result[$key];
|
||||
}
|
||||
}
|
||||
|
||||
if (($dependencies = $this->tracker->get('get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('get');
|
||||
foreach ($dependencies as $next_entity => $next_items)
|
||||
{
|
||||
$this->init($next_entity, $this->getGuids($next_items), $repo, $force);
|
||||
}
|
||||
}
|
||||
|
||||
if (($files = $this->tracker->get('file.get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('file.get');
|
||||
$this->file($files, $repo, $force);
|
||||
}
|
||||
|
||||
if (($folders = $this->tracker->get('folder.get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('folder.get');
|
||||
$this->folder($folders, $repo, $force);
|
||||
}
|
||||
|
||||
return $this->initResults;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset the items
|
||||
*
|
||||
* @param string $entity The target entity
|
||||
* @param array $items The global unique ids of the items
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function reset(string $entity, array $items): void
|
||||
{
|
||||
if (($class = $this->entities->get($entity)) === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container->get("{$class}.Remote.Get")->reset($items);
|
||||
|
||||
if (($dependencies = $this->tracker->get('get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('get');
|
||||
foreach ($dependencies as $next_entity => $next_items)
|
||||
{
|
||||
// we only reset direct children entities (in reset)
|
||||
$active = $this->getDirectChildrenGuids($next_items);
|
||||
if ($active !== [])
|
||||
{
|
||||
$this->reset($next_entity, $active);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($files = $this->tracker->get('file.get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('file.get');
|
||||
$this->container->get("File.Remote.Get")->reset($files);
|
||||
}
|
||||
|
||||
if (($folders = $this->tracker->get('folder.get')) !== null)
|
||||
{
|
||||
$this->tracker->remove('folder.get');
|
||||
$this->container->get("Folder.Remote.Get")->reset($folders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the files from the remote system.
|
||||
*
|
||||
* @param array $files The files.
|
||||
* @param object|null $repo The repository object to search. If null, all repos will be searched.
|
||||
* @param bool $force Force a local update (if item exist locally).
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function file(array $files, ?object $repo = null, bool $force = false): void
|
||||
{
|
||||
$result = $this->container->get("File.Remote.Get")->init($files, $repo, $force);
|
||||
|
||||
foreach (['local', 'not_found', 'added'] as $key)
|
||||
{
|
||||
if (!empty($result[$key]))
|
||||
{
|
||||
$this->initResults[$key] += $result[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the folders from the remote system.
|
||||
*
|
||||
* @param array $folders The folders.
|
||||
* @param object|null $repo The repository object to search. If null, all repos will be searched.
|
||||
* @param bool $force Force a local update (if item exist locally).
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function folder(array $folders, ?object $repo = null, bool $force = false): void
|
||||
{
|
||||
$result = $this->container->get("Folder.Remote.Get")->init($folders, $repo, $force);
|
||||
|
||||
foreach (['local', 'not_found', 'added'] as $key)
|
||||
{
|
||||
if (!empty($result[$key]))
|
||||
{
|
||||
$this->initResults[$key] += $result[$key];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract only the `value` property from an array of arrays or objects.
|
||||
*
|
||||
* This method supports mixed input types (arrays or objects)
|
||||
* and will extract the `value` from each entity as long as it is not empty.
|
||||
*
|
||||
* @param array $entities The entities keyed by GUID.
|
||||
*
|
||||
* @return array An indexed array of extracted `value` strings.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getDirectChildrenGuids(array $entities): array
|
||||
{
|
||||
$values = [];
|
||||
|
||||
foreach ($entities as $entity)
|
||||
{
|
||||
$value = null;
|
||||
|
||||
if (is_array($entity) && $entity['direction'] === 'in')
|
||||
{
|
||||
$value = $entity['value'] ?? null;
|
||||
}
|
||||
elseif (is_object($entity) && $entity->direction === 'in')
|
||||
{
|
||||
$value = $entity->value ?? null;
|
||||
}
|
||||
|
||||
if (!empty($value))
|
||||
{
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract only the `value` property from an array of arrays or objects.
|
||||
*
|
||||
* This method supports mixed input types (arrays or objects)
|
||||
* and will extract the `value` from each entity as long as it is not empty.
|
||||
*
|
||||
* @param array $entities The entities keyed by GUID.
|
||||
*
|
||||
* @return array An indexed array of extracted `value` strings.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getGuids(array $entities): array
|
||||
{
|
||||
$values = [];
|
||||
|
||||
foreach ($entities as $entity)
|
||||
{
|
||||
$value = null;
|
||||
|
||||
if (is_array($entity))
|
||||
{
|
||||
$value = $entity['value'] ?? null;
|
||||
}
|
||||
elseif (is_object($entity))
|
||||
{
|
||||
$value = $entity->value ?? null;
|
||||
}
|
||||
|
||||
if (!empty($value))
|
||||
{
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1,144 @@
|
||||
<?php
|
||||
/**
|
||||
* @package Joomla.Component.Builder
|
||||
*
|
||||
* @created 4th September, 2022
|
||||
* @author Llewellyn van der Merwe <https://dev.vdm.io>
|
||||
* @git Joomla Component Builder <https://git.vdm.dev/joomla/Component-Builder>
|
||||
* @copyright Copyright (C) 2015 Vast Development Method. All rights reserved.
|
||||
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||
*/
|
||||
|
||||
namespace VDM\Joomla\Componentbuilder\Package\Builder;
|
||||
|
||||
|
||||
use Joomla\DI\Container;
|
||||
use VDM\Joomla\Interfaces\Registryinterface as Entities;
|
||||
use VDM\Joomla\Componentbuilder\Package\Dependency\Tracker;
|
||||
|
||||
|
||||
/**
|
||||
* Package Builder Set
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
class Set
|
||||
{
|
||||
/**
|
||||
* The Entities Class.
|
||||
*
|
||||
* @var Entities
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Entities $entities;
|
||||
|
||||
/**
|
||||
* The Tracker Class.
|
||||
*
|
||||
* @var Tracker
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Tracker $tracker;
|
||||
|
||||
/**
|
||||
* The DI Container Class.
|
||||
*
|
||||
* @var Container
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected Container $container;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param Entities $entities The Entities Class.
|
||||
* @param Tracker $tracker The Tracker Class.
|
||||
* @param Container $container The container Class.
|
||||
*
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function __construct(Entities $entities, Tracker $tracker, Container $container)
|
||||
{
|
||||
$this->entities = $entities;
|
||||
$this->tracker = $tracker;
|
||||
$this->container = $container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save items remotely
|
||||
*
|
||||
* @param string $entity The target entity
|
||||
* @param array $guids The global unique id of the item
|
||||
*
|
||||
* @return void
|
||||
* @since 5.1.1
|
||||
*/
|
||||
public function items(string $entity, array $guids): void
|
||||
{
|
||||
if (($class = $this->entities->get($entity)) === null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
$this->container->get("{$class}.Remote.Set")->items($guids);
|
||||
|
||||
if (($dependencies = $this->tracker->get('set')) !== null)
|
||||
{
|
||||
$this->tracker->remove('set');
|
||||
foreach ($dependencies as $next_entity => $next_items)
|
||||
{
|
||||
$this->items($next_entity, $this->getGuids($next_items));
|
||||
}
|
||||
}
|
||||
|
||||
if (($files = $this->tracker->get('file.set')) !== null)
|
||||
{
|
||||
$this->tracker->remove('file.set');
|
||||
$this->container->get("File.Remote.Set")->items($files);
|
||||
}
|
||||
|
||||
if (($folders = $this->tracker->get('folder.set')) !== null)
|
||||
{
|
||||
$this->tracker->remove('folder.set');
|
||||
$this->container->get("Folder.Remote.Set")->items($folders);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract only the `value` property from an array of arrays or objects.
|
||||
*
|
||||
* This method supports mixed input types (arrays or objects)
|
||||
* and will extract the `value` from each entity as long as it is not empty.
|
||||
*
|
||||
* @param array $entities The entities keyed by GUID.
|
||||
*
|
||||
* @return array An indexed array of extracted `value` strings.
|
||||
* @since 5.1.1
|
||||
*/
|
||||
protected function getGuids(array $entities): array
|
||||
{
|
||||
$values = [];
|
||||
|
||||
foreach ($entities as $entity)
|
||||
{
|
||||
$value = null;
|
||||
|
||||
if (is_array($entity))
|
||||
{
|
||||
$value = $entity['value'] ?? null;
|
||||
}
|
||||
elseif (is_object($entity))
|
||||
{
|
||||
$value = $entity->value ?? null;
|
||||
}
|
||||
|
||||
if (!empty($value))
|
||||
{
|
||||
$values[] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $values;
|
||||
}
|
||||
}
|
||||
|
@@ -0,0 +1 @@
|
||||
<html><body bgcolor="#FFFFFF"></body></html>
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user