diff --git a/src/Console/bin/bones b/src/Console/bin/bones index f8a646e..4e3cd43 100644 --- a/src/Console/bin/bones +++ b/src/Console/bin/bones @@ -11,441 +11,443 @@ namespace Bones\SemVer\Exceptions { - use Exception; + use Exception; - class InvalidVersionException extends Exception {} + class InvalidVersionException extends Exception + { + } } namespace Bones\SemVer\Traits { - use Bones\SemVer\Version; + use Bones\SemVer\Version; - trait Comparable - { - /** - * Check if this Version object is greater than another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is greater than the comparing - * object, otherwise false - */ - public function gt(Version $version): bool + trait Comparable { - return self::compare($this, $version) > 0; - } + /** + * Check if this Version object is greater than another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is greater than the comparing + * object, otherwise false + */ + public function gt(Version $version): bool + { + return self::compare($this, $version) > 0; + } - /** - * Compare two versions. Returns -1, 0 or 1 if the first version is less - * than, equal to or greater than the second version respectively. - * - * @param Version $version1 An instance of SemVer/Version - * @param Version $version2 An instance of SemVer/Version - */ - public static function compare(Version $version1, Version $version2): int - { - $v1 = [$version1->major, $version1->minor, $version1->patch]; - $v2 = [$version2->major, $version2->minor, $version2->patch]; - - $baseComparison = $v1 <=> $v2; - - if ($baseComparison !== 0) { - return $baseComparison; - } - - if ($version1->preRelease !== null && $version2->preRelease === null) { - return -1; - } - - if ($version1->preRelease === null && $version2->preRelease !== null) { - return 1; - } - - $v1preReleaseParts = explode('.', $version1->preRelease ?? ''); - $v2preReleaseParts = explode('.', $version2->preRelease ?? ''); - - $preReleases1 = array_pad( - $v1preReleaseParts, - count($v2preReleaseParts), - null - ); - $preReleases2 = array_pad( - $v2preReleaseParts, - count($v1preReleaseParts), - null - ); - - return $preReleases1 <=> $preReleases2; - } + /** + * Compare two versions. Returns -1, 0 or 1 if the first version is less + * than, equal to or greater than the second version respectively. + * + * @param Version $version1 An instance of SemVer/Version + * @param Version $version2 An instance of SemVer/Version + */ + public static function compare(Version $version1, Version $version2): int + { + $v1 = [$version1->major, $version1->minor, $version1->patch]; + $v2 = [$version2->major, $version2->minor, $version2->patch]; - /** - * Check if this Version object is less than another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is less than the comparing - * object, otherwise false - */ - public function lt(Version $version): bool - { - return self::compare($this, $version) < 0; - } + $baseComparison = $v1 <=> $v2; - /** - * Check if this Version object is equal to than another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is equal to the comparing - * object, otherwise false - */ - public function eq(Version $version): bool - { - return self::compare($this, $version) === 0; - } + if ($baseComparison !== 0) { + return $baseComparison; + } - /** - * Check if this Version object is not equal to another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is not equal to the comparing - * object, otherwise false - */ - public function neq(Version $version): bool - { - return self::compare($this, $version) !== 0; - } + if ($version1->preRelease !== null && $version2->preRelease === null) { + return -1; + } - /** - * Check if this Version object is greater than or equal to another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is greater than or equal to the - * comparing object, otherwise false - */ - public function gte(Version $version): bool - { - return self::compare($this, $version) >= 0; - } + if ($version1->preRelease === null && $version2->preRelease !== null) { + return 1; + } - /** - * Check if this Version object is less than or equal to another. - * - * @param Version $version An instance of SemVer/Version - * - * @return bool True if this Version object is less than or equal to the - * comparing object, otherwise false - */ - public function lte(Version $version): bool - { - return self::compare($this, $version) <= 0; - } - } + $v1preReleaseParts = explode('.', $version1->preRelease ?? ''); + $v2preReleaseParts = explode('.', $version2->preRelease ?? ''); + + $preReleases1 = array_pad( + $v1preReleaseParts, + count($v2preReleaseParts), + null + ); + $preReleases2 = array_pad( + $v2preReleaseParts, + count($v1preReleaseParts), + null + ); + + return $preReleases1 <=> $preReleases2; + } - trait Incrementable - { - /** - * Increment the major version value by one. - * - * @return self This Version object - */ - public function incrementMajor(): self - { - $this->setMajor($this->major + 1); + /** + * Check if this Version object is less than another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is less than the comparing + * object, otherwise false + */ + public function lt(Version $version): bool + { + return self::compare($this, $version) < 0; + } - return $this; - } + /** + * Check if this Version object is equal to than another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is equal to the comparing + * object, otherwise false + */ + public function eq(Version $version): bool + { + return self::compare($this, $version) === 0; + } - /** - * Increment the minor version value by one. - * - * @return self This Version object - */ - public function incrementMinor(): self - { - $this->setMinor($this->minor + 1); + /** + * Check if this Version object is not equal to another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is not equal to the comparing + * object, otherwise false + */ + public function neq(Version $version): bool + { + return self::compare($this, $version) !== 0; + } + + /** + * Check if this Version object is greater than or equal to another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is greater than or equal to the + * comparing object, otherwise false + */ + public function gte(Version $version): bool + { + return self::compare($this, $version) >= 0; + } - return $this; + /** + * Check if this Version object is less than or equal to another. + * + * @param Version $version An instance of SemVer/Version + * + * @return bool True if this Version object is less than or equal to the + * comparing object, otherwise false + */ + public function lte(Version $version): bool + { + return self::compare($this, $version) <= 0; + } } - /** - * Increment the patch version value by one. - * - * @return self This Version object - */ - public function incrementPatch(): self + trait Incrementable { - $this->setPatch($this->patch + 1); + /** + * Increment the major version value by one. + * + * @return self This Version object + */ + public function incrementMajor(): self + { + $this->setMajor($this->major + 1); - return $this; - } + return $this; + } - /** - * Increment the pre-release version value by one. - * - * @return self This Version object - */ - public function incrementPreRelease(): self - { - if (empty($this->preRelease)) { - $this->incrementPatch(); - $this->setPreRelease('1'); + /** + * Increment the minor version value by one. + * + * @return self This Version object + */ + public function incrementMinor(): self + { + $this->setMinor($this->minor + 1); + + return $this; + } + + /** + * Increment the pre-release version value by one. + * + * @return self This Version object + */ + public function incrementPreRelease(): self + { + if (empty($this->preRelease)) { + $this->incrementPatch(); + $this->setPreRelease('1'); + + return $this; + } + + $identifiers = explode('.', $this->preRelease); - return $this; - } + if (!is_numeric(end($identifiers))) { + $this->setPreRelease(implode('.', [$this->preRelease, '1'])); - $identifiers = explode('.', $this->preRelease); + return $this; + } - if (!is_numeric(end($identifiers))) { - $this->setPreRelease(implode('.', [$this->preRelease, '1'])); + array_push($identifiers, (string)((int)array_pop($identifiers) + 1)); - return $this; - } + $this->setPreRelease(implode('.', $identifiers)); - array_push($identifiers, (string) ((int) array_pop($identifiers) + 1)); + return $this; + } - $this->setPreRelease(implode('.', $identifiers)); + /** + * Increment the patch version value by one. + * + * @return self This Version object + */ + public function incrementPatch(): self + { + $this->setPatch($this->patch + 1); - return $this; + return $this; + } } - } } namespace Bones\SemVer { - use Bones\SemVer\Exceptions\InvalidVersionException; - use Bones\SemVer\Traits\Comparable; - use Bones\SemVer\Traits\Incrementable; + use Bones\SemVer\Exceptions\InvalidVersionException; + use Bones\SemVer\Traits\Comparable; + use Bones\SemVer\Traits\Incrementable; - /** - * @property int $major Major release number - * @property int $minor Minor release number - * @property int $patch Patch release number - * @property string|null $preRelease Pre-release value - * @property string|null $build Build release value - */ - class Version - { - use Comparable; - use Incrementable; + /** + * @property int $major Major release number + * @property int $minor Minor release number + * @property int $patch Patch release number + * @property string|null $preRelease Pre-release value + * @property string|null $build Build release value + */ + class Version + { + use Comparable; + use Incrementable; - /** @var int Major release number */ - protected $major; + /** @var int Major release number */ + protected $major; - /** @var int Minor release number */ - protected $minor; + /** @var int Minor release number */ + protected $minor; - /** @var int Patch release number */ - protected $patch; + /** @var int Patch release number */ + protected $patch; - /** @var string|null Pre-release value */ - protected $preRelease; + /** @var string|null Pre-release value */ + protected $preRelease; - /** @var string|null Build release value */ - protected $build; + /** @var string|null Build release value */ + protected $build; - /** - * Class constructor, runs on object creation. - * - * @param string $version Version string - * - * @throws \Bones\SemVer\Exceptions\InvalidVersionException - */ - public function __construct(string $version = '0.1.0') - { - $this->setVersion($version); - } + /** + * Class constructor, runs on object creation. + * + * @param string $version Version string + * + * @throws InvalidVersionException + */ + public function __construct(string $version = '0.1.0') + { + $this->setVersion($version); + } - /** - * Set (override) the entire version value. - * - * @param string $version Version string - * - * @return self This Version object - * @throws \Bones\SemVer\Exceptions\InvalidVersionException - * - */ - public function setVersion(string $version): self - { - $semverRegex = - '/^v?(?\d+)\.(?\d+)\.(?\d+)(?:-(?[0-9A-Za-z-.]+))?(?:\+(?[0-9A-Za-z-.]+)?)?$/'; - - if (!preg_match($semverRegex, $version, $matches)) { - throw new InvalidVersionException( - 'Invalid semantic version string provided' - ); - } - - $this->major = (int) $matches['major']; - $this->minor = (int) $matches['minor']; - $this->patch = (int) $matches['patch']; - $this->preRelease = $matches['pre_release'] ?? null; - $this->build = $matches['build'] ?? null; - - return $this; - } + /** + * Set (override) the entire version value. + * + * @param string $version Version string + * + * @return self This Version object + * @throws InvalidVersionException + * + */ + public function setVersion(string $version): self + { + $semverRegex = + '/^v?(?\d+)\.(?\d+)\.(?\d+)(?:-(?[0-9A-Za-z-.]+))?(?:\+(?[0-9A-Za-z-.]+)?)?$/'; + + if (!preg_match($semverRegex, $version, $matches)) { + throw new InvalidVersionException( + 'Invalid semantic version string provided' + ); + } - /** - * Magic get method; provides access to version properties. - * - * @param string $property Version property - * - * @return mixed Version property value - */ - public function __get(string $property) - { - return $this->$property; - } + $this->major = (int)$matches['major']; + $this->minor = (int)$matches['minor']; + $this->patch = (int)$matches['patch']; + $this->preRelease = $matches['pre_release'] ?? null; + $this->build = $matches['build'] ?? null; - /** - * Magic toString method; allows object interaction as if it were a string. - * - * @return string Current version string - */ - public function __toString(): string - { - $version = implode('.', [$this->major, $this->minor, $this->patch]); + return $this; + } - if (!empty($this->preRelease)) { - $version .= '-' . $this->preRelease; - } + /** + * Attempt to parse an incomplete version string. + * + * Examples: 'v1', 'v1.2', 'v1-beta.4', 'v1.3+007' + * + * @param string $version Version string + * + * @return self This Version object + * @throws InvalidVersionException + * + */ + public static function parse(string $version): self + { + $semverRegex = + '/^v?(?\d+)(?:\.(?\d+)(?:\.(?\d+))?)?(?:-(?[0-9A-Za-z-.]+))?(?:\+(?[0-9A-Za-z-.]+)?)?$/'; + + if (!preg_match($semverRegex, $version, $matches)) { + throw new InvalidVersionException( + 'Invalid semantic version string provided' + ); + } - if (!empty($this->build)) { - $version .= '+' . $this->build; - } + $version = sprintf( + '%s.%s.%s', + $matches['major'], + $matches['minor'] ?? 0, + $matches['patch'] ?? 0 + ); - return $version; - } + if (!empty($matches['pre_release'])) { + $version .= '-' . $matches['pre_release']; + } - /** - * Attempt to parse an incomplete version string. - * - * Examples: 'v1', 'v1.2', 'v1-beta.4', 'v1.3+007' - * - * @param string $version Version string - * - * @return self This Version object - * @throws \Bones\SemVer\Exceptions\InvalidVersionException - * - */ - public static function parse(string $version): self - { - $semverRegex = - '/^v?(?\d+)(?:\.(?\d+)(?:\.(?\d+))?)?(?:-(?[0-9A-Za-z-.]+))?(?:\+(?[0-9A-Za-z-.]+)?)?$/'; - - if (!preg_match($semverRegex, $version, $matches)) { - throw new InvalidVersionException( - 'Invalid semantic version string provided' - ); - } - - $version = sprintf( - '%s.%s.%s', - $matches['major'], - $matches['minor'] ?? 0, - $matches['patch'] ?? 0 - ); - - if (!empty($matches['pre_release'])) { - $version .= '-' . $matches['pre_release']; - } - - if (!empty($matches['build'])) { - $version .= '+' . $matches['build']; - } - - return new self($version); - } + if (!empty($matches['build'])) { + $version .= '+' . $matches['build']; + } - /** - * Set the major version to a custom value. - * - * @param int $value Positive integer value - * - * @return self This Version object - */ - public function setMajor(int $value): self - { - $this->major = $value; - $this->setMinor(0); + return new self($version); + } - return $this; - } + /** + * Magic get method; provides access to version properties. + * + * @param string $property Version property + * + * @return mixed Version property value + */ + public function __get(string $property) + { + return $this->$property; + } - /** - * Set the minor version to a custom value. - * - * @param int $value Positive integer value - * - * @return self This Version object - */ - public function setMinor(int $value): self - { - $this->minor = $value; - $this->setPatch(0); + /** + * Magic toString method; allows object interaction as if it were a string. + * + * @return string Current version string + */ + public function __toString(): string + { + $version = implode('.', [$this->major, $this->minor, $this->patch]); - return $this; - } + if (!empty($this->preRelease)) { + $version .= '-' . $this->preRelease; + } - /** - * Set the patch version to a custom value. - * - * @param int $value Positive integer value - * - * @return self This Version object - */ - public function setPatch(int $value): self - { - $this->patch = $value; - $this->setPreRelease(null); - $this->setBuild(null); + if (!empty($this->build)) { + $version .= '+' . $this->build; + } - return $this; - } + return $version; + } - /** - * Set the pre-release string to a custom value. - * - * @param string|null $value A new pre-release value - * - * @return self This Version object - */ - public function setPreRelease($value): self - { - $this->preRelease = $value; + /** + * Set the major version to a custom value. + * + * @param int $value Positive integer value + * + * @return self This Version object + */ + public function setMajor(int $value): self + { + $this->major = $value; + $this->setMinor(0); - return $this; - } + return $this; + } - /** - * Set the build string to a custom value. - * - * @param string|null $value A new build value - * - * @return self This Version object - */ - public function setBuild($value): self - { - $this->build = $value; + /** + * Set the minor version to a custom value. + * + * @param int $value Positive integer value + * + * @return self This Version object + */ + public function setMinor(int $value): self + { + $this->minor = $value; + $this->setPatch(0); - return $this; - } + return $this; + } - /** - * Get the version string prefixed with a custom string. - * - * @param string $prefix String to prepend to the version string - * (default: 'v') - * - * @return string Prefixed version string - */ - public function prefix(string $prefix = 'v'): string - { - return $prefix . (string) $this; + /** + * Set the patch version to a custom value. + * + * @param int $value Positive integer value + * + * @return self This Version object + */ + public function setPatch(int $value): self + { + $this->patch = $value; + $this->setPreRelease(null); + $this->setBuild(null); + + return $this; + } + + /** + * Set the pre-release string to a custom value. + * + * @param string|null $value A new pre-release value + * + * @return self This Version object + */ + public function setPreRelease($value): self + { + $this->preRelease = $value; + + return $this; + } + + /** + * Set the build string to a custom value. + * + * @param string|null $value A new build value + * + * @return self This Version object + */ + public function setBuild($value): self + { + $this->build = $value; + + return $this; + } + + /** + * Get the version string prefixed with a custom string. + * + * @param string $prefix String to prepend to the version string + * (default: 'v') + * + * @return string Prefixed version string + */ + public function prefix(string $prefix = 'v'): string + { + return $prefix . (string)$this; + } } - } } /* @@ -458,268 +460,265 @@ namespace Bones\SemVer { */ namespace Bones { - /** - * The minimum PHP version required to run Bones. - */ - define('WPBONES_MINIMAL_PHP_VERSION', '7.4'); - - /** - * MARK: The WP Bones command line version. - */ - define('WPBONES_COMMAND_LINE_VERSION', '1.4.15'); - - use Bones\SemVer\Version; - use Exception; - - if (!function_exists('semver')) { - /** - * Create a SemVer version object. - * - * @throws \Bones\SemVer\Exceptions\InvalidVersionException - */ - function semver(string $string): Version - { - return new Version($string); - } - } - - if (version_compare(PHP_VERSION, WPBONES_MINIMAL_PHP_VERSION) < 0) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . - 'You must run with PHP version ' . - WPBONES_MINIMAL_PHP_VERSION . - ' or greater'; - echo "\033[0m\n\n"; - exit(); - } - - /** - * @class BonesCommandLine - */ - class BonesCommandLine - { /** - * WP Bones version + * The minimum PHP version required to run Bones. */ - const VERSION = WPBONES_COMMAND_LINE_VERSION; + define('WPBONES_MINIMAL_PHP_VERSION', '7.4'); /** - * Used for additional kernel command. - * - * @var null + * MARK: The WP Bones command line version. */ - protected $kernel = null; + define('WPBONES_COMMAND_LINE_VERSION', '1.5.0'); - /** - * List of files and folders to skip during the deployment. - * - * @var array - */ - protected $skipWhenDeploy = []; - - /** - * Base folder during the deployment. - * - * @var string - */ - protected $rootDeploy = ''; + use Bones\SemVer\Exceptions\InvalidVersionException; + use Bones\SemVer\Version; + use Exception; - public function __construct() - { - $this->boot(); + if (!function_exists('semver')) { + /** + * Create a SemVer version object. + * + * @throws InvalidVersionException + */ + function semver(string $string): Version + { + return new Version($string); + } } - /** - * This is a special bootstrap in order to avoid the WordPress and kernel environment - * when we have to rename the plugin and vendor structure. - * - */ - public function boot() - { - $arguments = $this->arguments(); - - // load the WordPress environment and the plugin - $this->loadWordPress(); - - // load the console kernel - $this->loadKernel(); - - // we won't load the WordPress environment for the following commands - if (empty($arguments) || $this->isCommand('--help')) { - $this->help(); - } - // rename - elseif ($this->isCommand('rename')) { - $this->rename($this->commandParams()); - } - // install - elseif ($this->isCommand('install')) { - $this->install($this->commandParams()); - } - // Update - elseif ($this->isCommand('update')) { - $this->update(); - } - // go ahead... - else { - // handle the rest of the commands except rename - $this->handle(); - } + if (version_compare(PHP_VERSION, WPBONES_MINIMAL_PHP_VERSION) < 0) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . + 'You must run with PHP version ' . + WPBONES_MINIMAL_PHP_VERSION . + ' or greater'; + echo "\033[0m\n\n"; + exit(); } /** - * Return the arguments after "php bones". - * - * @param int $index Optional. Index of argument. - * If NULL will be returned the whole array. - * - * @return mixed|array + * @class BonesCommandLine */ - protected function arguments($index = null) + class BonesCommandLine { - $argv = $_SERVER['argv']; + /** + * WP Bones version + */ + const VERSION = WPBONES_COMMAND_LINE_VERSION; - // strip the application name - array_shift($argv); + /** + * Used for additional kernel command. + * + * @var null + */ + protected $kernel = null; - return $index ? $argv[$index] ?? null : $argv; - } + /** + * List of files and folders to skip during the deployment. + * + * @var array + */ + protected $skipWhenDeploy = []; - /** - * Load WordPress core and all environment. - * - */ - protected function loadWordPress() - { - try { - /* - |-------------------------------------------------------------------------- - | Load WordPress - |-------------------------------------------------------------------------- - | - | We have to load the WordPress environment. - | - */ - $currentDir = $_SERVER['PWD'] ?? __DIR__; - $wpLoadPath = dirname(dirname(dirname($currentDir))) . '/wp-load.php'; + /** + * Base folder during the deployment. + * + * @var string + */ + protected $rootDeploy = ''; - if (!file_exists($wpLoadPath)) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . - 'You must be inside "wp-content/plugins/" folders'; - echo "\033[0m\n\n"; - exit(); + public function __construct() + { + $this->boot(); } - require $wpLoadPath; - } catch (Exception $e) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . 'Can\'t load WordPress'; - echo "\033[0m\n\n"; - } + /** + * This is a special bootstrap in order to avoid the WordPress and kernel environment + * when we have to rename the plugin and vendor structure. + * + */ + public function boot() + { + $arguments = $this->arguments(); + + // load the WordPress environment and the plugin + $this->loadWordPress(); + + // load the console kernel + $this->loadKernel(); + + // we won't load the WordPress environment for the following commands + if (empty($arguments) || $this->isCommand('--help')) { + $this->help(); + } // rename + elseif ($this->isCommand('rename')) { + $this->rename($this->commandParams()); + } // install + elseif ($this->isCommand('install')) { + $this->install($this->commandParams()); + } // Update + elseif ($this->isCommand('update')) { + $this->update(); + } // go ahead... + else { + // handle the rest of the commands except rename + $this->handle(); + } + } - try { - /* - |-------------------------------------------------------------------------- - | Register The Auto Loader - |-------------------------------------------------------------------------- - | - | Composer provides a convenient, automatically generated class loader - | for our application. We just need to utilize it! We'll require it - | into the script here so that we do not have to worry about the - | loading of any classes "manually". Feels great to relax. - | - */ + /** + * Return the arguments after "php bones". + * + * @param int $index Optional. Index of argument. + * If NULL will be returned the whole array. + * + * @return mixed|array + */ + protected function arguments($index = null) + { + $argv = $_SERVER['argv']; + + // strip the application name + array_shift($argv); - if (file_exists(__DIR__ . '/vendor/autoload.php')) { - require __DIR__ . '/vendor/autoload.php'; + return $index ? $argv[$index] ?? null : $argv; } - } catch (Exception $e) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . 'Can\'t load Composer'; - } - try { - /* - |-------------------------------------------------------------------------- - | Load this plugin env - |-------------------------------------------------------------------------- - | - */ + /** + * Load WordPress core and all environment. + * + */ + protected function loadWordPress() + { + try { + /* + |-------------------------------------------------------------------------- + | Load WordPress + |-------------------------------------------------------------------------- + | + | We have to load the WordPress environment. + | + */ + $currentDir = $_SERVER['PWD'] ?? __DIR__; + $wpLoadPath = dirname(dirname(dirname($currentDir))) . '/wp-load.php'; + + if (!file_exists($wpLoadPath)) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . + 'You must be inside "wp-content/plugins/" folders'; + echo "\033[0m\n\n"; + exit(); + } + + require $wpLoadPath; + } catch (Exception $e) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . 'Can\'t load WordPress'; + echo "\033[0m\n\n"; + } + + try { + /* + |-------------------------------------------------------------------------- + | Register The Auto Loader + |-------------------------------------------------------------------------- + | + | Composer provides a convenient, automatically generated class loader + | for our application. We just need to utilize it! We'll require it + | into the script here so that we do not have to worry about the + | loading of any classes "manually". Feels great to relax. + | + */ + + if (file_exists(__DIR__ . '/vendor/autoload.php')) { + require __DIR__ . '/vendor/autoload.php'; + } + } catch (Exception $e) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . 'Can\'t load Composer'; + } + + try { + /* + |-------------------------------------------------------------------------- + | Load this plugin env + |-------------------------------------------------------------------------- + | + */ - if (file_exists(__DIR__ . '/bootstrap/plugin.php')) { - require_once __DIR__ . '/bootstrap/plugin.php'; + if (file_exists(__DIR__ . '/bootstrap/plugin.php')) { + require_once __DIR__ . '/bootstrap/plugin.php'; + } + } catch (Exception $e) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . 'Can\'t load this plugin env'; + } } - } catch (Exception $e) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . 'Can\'t load this plugin env'; - } - } - /** - * Check and load for console kernel extensions. - * - */ - protected function loadKernel() - { - // current plugin name and namespace - $namespace = $this->getNamespace(); + /** + * Check and load for console kernel extensions. + * + */ + protected function loadKernel() + { + // current plugin name and namespace + $namespace = $this->getNamespace(); - $kernelClass = "{$namespace}\\Console\\Kernel"; - $WPBonesKernelClass = "{$namespace}\\WPBones\\Foundation\\Console\\Kernel"; + $kernelClass = "{$namespace}\\Console\\Kernel"; + $WPBonesKernelClass = "{$namespace}\\WPBones\\Foundation\\Console\\Kernel"; - try { - if (class_exists($WPBonesKernelClass) && class_exists($kernelClass)) { - $this->kernel = new $kernelClass(); + try { + if (class_exists($WPBonesKernelClass) && class_exists($kernelClass)) { + $this->kernel = new $kernelClass(); + } + } catch (Exception $e) { + echo "\n\033[33;5;82mWarning!!\n"; + echo "\n\033[38;5;82m\t" . 'Can\'t load console kernel'; + } } - } catch (Exception $e) { - echo "\n\033[33;5;82mWarning!!\n"; - echo "\n\033[38;5;82m\t" . 'Can\'t load console kernel'; - } - } - /** - * Return the current Plugin namespace defined in the namespace file. - * - * @return string - */ - public function getNamespace(): string - { - [$null, $namespace] = $this->getPluginNameAndNamespace(); + /** + * Return the current Plugin namespace defined in the namespace file. + * + * @return string + */ + public function getNamespace(): string + { + [$null, $namespace] = $this->getPluginNameAndNamespace(); - return $namespace; - } + return $namespace; + } - /** - * Return the current Plugin name and namespace defined in the namespace file. - * - * @return array - */ - public function getPluginNameAndNamespace(): array - { - return explode(',', file_get_contents('namespace')); - } + /** + * Return the current Plugin name and namespace defined in the namespace file. + * + * @return array + */ + public function getPluginNameAndNamespace(): array + { + return explode(',', file_get_contents('namespace')); + } - /** - * Return TRUE if the command is in console argument. - * - * @param string $command Bones command to check. - * @return bool - */ - protected function isCommand($command): bool - { - $arguments = $this->arguments(); + /** + * Return TRUE if the command is in console argument. + * + * @param string $command Bones command to check. + * @return bool + */ + protected function isCommand($command): bool + { + $arguments = $this->arguments(); - return $command === ($arguments[0] ?? ''); - } + return $command === ($arguments[0] ?? ''); + } - /** - * Display the full help. - * - */ - protected function help() - { - echo ' + /** + * Display the full help. + * + */ + protected function help() + { + echo ' o o o--o o--o | | | | | | o o o O--o O--o o-o o-o o-o o-o @@ -728,1836 +727,1881 @@ namespace Bones { '; - $this->info("\nBones Version " . self::VERSION . "\n"); - $this->info('Current plugin name and namespace:'); - $this->line(" '{$this->getPluginName()}', '{$this->getNamespace()}'\n"); - $this->info('Usage:'); - $this->line(" command [options] [arguments]\n"); - $this->info('Available commands:'); - $this->line(' deploy Create a deploy version'); - $this->line(' install Install a new WP Bones plugin'); - $this->line( - ' optimize Run composer dump-autoload with -o option' - ); - $this->line( - ' rename Rename the plugin name and the namespace' - ); - $this->line(' require Install a WP Bones package'); - $this->line(' tinker Interact with your application'); - $this->line(' update Update the Framework'); - $this->line(' version Update the Plugin version'); - $this->info('migrate'); - $this->line(' migrate:create Create a new Migration'); - $this->info('make'); - $this->line( - ' make:ajax Create a new Ajax service provider class' - ); - $this->line(' make:api Create a new API controller class'); - $this->line(' make:controller Create a new controller class'); - $this->line(' make:console Create a new Bones command'); - $this->line( - ' make:cpt Create a new Custom Post Type service provider class' - ); - $this->line( - ' make:ctt Create a new Custom Taxonomy Type service provider class' - ); - $this->line( - ' make:shortcode Create a new Shortcode service provider class' - ); - $this->line( - ' make:provider Create a new service provider class' - ); - $this->line( - ' make:widget Create a new Widget service provider class' - ); - $this->line(' make:model Create a new database model class'); - $this->line( - ' make:eloquent-model Create a new Eloquent database model class' - ); - - if ($this->kernel && $this->kernel->hasCommands()) { - $this->info('Extensions'); - $this->kernel->displayHelp(); - } - - echo "\n\n"; - } + $this->info("\nBones Version " . self::VERSION . "\n"); + $this->info('Current plugin filename, name and namespace:'); + $this->line(" '{$this->getMainPluginFile()}', '{$this->getPluginName()}', '{$this->getNamespace()}'\n"); + $this->info('Usage:'); + $this->line(" command [options] [arguments]\n"); + $this->info('Available commands:'); + $this->line(' deploy Create a deploy version'); + $this->line(' install Install a new WP Bones plugin'); + $this->line( + ' optimize Run composer dump-autoload with -o option' + ); + $this->line( + ' rename Rename the plugin name and the namespace' + ); + $this->line(' require Install a WP Bones package'); + $this->line(' tinker Interact with your application'); + $this->line(' update Update the Framework'); + $this->line(' version Update the Plugin version'); + $this->info('migrate'); + $this->line(' migrate:create Create a new Migration'); + $this->info('make'); + $this->line( + ' make:ajax Create a new Ajax service provider class' + ); + $this->line(' make:api Create a new API controller class'); + $this->line(' make:controller Create a new controller class'); + $this->line(' make:console Create a new Bones command'); + $this->line( + ' make:cpt Create a new Custom Post Type service provider class' + ); + $this->line( + ' make:ctt Create a new Custom Taxonomy Type service provider class' + ); + $this->line( + ' make:shortcode Create a new Shortcode service provider class' + ); + $this->line( + ' make:provider Create a new service provider class' + ); + $this->line( + ' make:widget Create a new Widget service provider class' + ); + $this->line(' make:model Create a new database model class'); + $this->line( + ' make:eloquent-model Create a new Eloquent database model class' + ); + + if ($this->kernel && $this->kernel->hasCommands()) { + $this->info('Extensions'); + $this->kernel->displayHelp(); + } - /** - * Return true if the command is available in the system. - * - * @return string - */ - protected function isCommandAvailable($command) - { - $whereCommand = (PHP_OS_FAMILY === 'Windows') ? 'where' : 'command -v'; - $output = shell_exec("$whereCommand $command"); - return !empty($output); - } + echo "\n\n"; + } - /** - * Returns the available package manager - * - * @return string|null The name of the available package manager (yarn, npm, pnpm, bun) or null if none is available. - */ - protected function getAvailablePackageManager() - { - $packageManagers = ['yarn', 'npm', 'pnpm', 'bun']; + /** + * Commodity to display a message in the console. + * + * @param string $str The message to display. + */ + protected function info($str) + { + echo "\033[38;5;213m" . $str; + echo "\033[0m\n"; + } - foreach ($packageManagers as $manager) { - if ($this->isCommandAvailable($manager)) { - return $manager; + /** + * Commodity to display a message in the console. + * + * @param string $str The message to display. + */ + protected function line($str) + { + echo "\033[38;5;82m" . $str; + echo "\033[0m\n"; } - } - return null; - } + /** + * Return the default Plugin filename as snake case from the plugin name. + * + * @return string + */ + public function getMainPluginFile($pluginName = ""): string + { + if (empty($pluginName)) { + $pluginName = $this->getPluginName(); + } + return strtolower(str_replace(' ', '-', $pluginName)) . '.php'; + } - /** - * Commodity to display a message in the console. - * - * @param string $str The message to display. - */ - protected function info($str) - { - echo "\033[38;5;213m" . $str; - echo "\033[0m\n"; - } + /** + * Return the current Plugin name defined in the namespace file. + * + * @return string + */ + public function getPluginName(): string + { + [$plugin_name] = $this->getPluginNameAndNamespace(); - /** - * Commodity to display a message in the console. - * - * @param string $str The message to display. - */ - protected function line($str) - { - echo "\033[38;5;82m" . $str; - echo "\033[0m\n"; - } + return $plugin_name; + } - /** - * Return the current Plugin name defined in the namespace file. - * - * @return string - */ - public function getPluginName(): string - { - [$plugin_name] = $this->getPluginNameAndNamespace(); + /** + * This is the most important function of WP Bones. + * Here we will rename all occurrences of the plugin name and namespace. + * The default plugin name is 'WP Kirk' and the default namespace is 'WPKirk'. + * Here we will create also the slug used in the plugin. + * + * For example, if the plugin name is 'My WP Plugin' + * + * My WP Plugin Name of plugin + * MyWPPlugin Namespace, see [PSR-4 autoload standard](http://www.php-fig.org/psr/psr-4/) + * my_wp_plugin_slug Plugin slug + * my_wp_plugin_vars Plugin vars used for CPT, taxonomy, etc. + * my-wp-plugin Internal id used for css, js and less files + * + * As you can see we're going to create all namespace/id from the plugin name. + * + * @brief Rename the plugin + * + */ + protected function rename($args) + { + if ($this->isHelp()) { + $this->info('Usage:'); + $this->line(' php bones rename [options] '); + $this->info('Available options:'); + $this->line(' --reset Reset the plugin name and namespace'); + $this->line(' --update Rename after an update. For example after install a new package'); + exit(); + } - return $plugin_name; - } + $arg_option_plugin_name = $args[0] ?? null; + + switch ($arg_option_plugin_name) { + case '--reset': + $this->resetPluginNameAndNamespace(); + break; + case '--update': + $this->updatePluginNameAndNamespace(); + break; + default: + [$search_plugin_name, $search_namespace, $plugin_name, $namespace, $mainPluginFile] = $this->getAskPluginNameAndNamespace($args); + $this->info("\nThe new plugin filename, name and namespace will be '{$mainPluginFile}', '{$plugin_name}', '{$namespace}'"); + $yesno = $this->ask('Continue (y/n)', 'n'); + if (strtolower($yesno) != 'y') { + return; + } + $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); + break; + } + } - /** - * This is the most important function of WP Bones. - * Here we will rename all occurrences of the plugin name and namespace. - * The default plugin name is 'WP Kirk' and the default namespace is 'WPKirk'. - * Here we will create also the slug used in the plugin. - * - * For example, if the plugin name is 'My WP Plugin' - * - * My WP Plugin Name of plugin - * MyWPPlugin Namespace, see [PSR-4 autoload standard](http://www.php-fig.org/psr/psr-4/) - * my_wp_plugin_slug Plugin slug - * my_wp_plugin_vars Plugin vars used for CPT, taxonomy, etc. - * my-wp-plugin Internal id used for css, js and less files - * - * As you can see we're going to create all namespace/id from the plugin name. - * - * @brief Rename the plugin - * - */ - protected function rename($args) - { - if ($this->isHelp()) { - $this->info('Usage:'); - $this->line(' php bones rename [options] '); - $this->info('Available options:'); - $this->line(' --reset Reset the plugin name and namespace'); - $this->line(' --update Rename after an update. For example after install a new package'); - exit(); - } - - $arg_option_plugin_name = $args[0] ?? null; - - switch ($arg_option_plugin_name) { - case '--reset': - $this->resetPluginNameAndNamespace(); - break; - case '--update': - $this->updatePluginNameAndNamespace(); - break; - default: - [$search_plugin_name, $search_namespace, $plugin_name, $namespace] = $this->getAskPluginNameAndNamespace($args); - $this->info("\nThe new plugin name and namespace will be '{$plugin_name}', '{$namespace}'"); - $yesno = $this->ask('Continue (y/n)', 'n'); - if (strtolower($yesno) != 'y') { - return; - } - $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); - break; - } - } + /** + * Commodity function to check if help has been requested. + * + * @param string $str Optional. Command to check. + * + * @return bool + */ + protected function isHelp($str = null): bool + { + if (!is_null($str)) { + return empty($str) || $str === '--help'; + } - /** - * Get the plugin name and namespace from args or ask them from the console - */ - protected function getAskPluginNameAndNamespace($args) - { - // Get the current plugin name and namespace - $search_plugin_name = $this->getPluginName(); - $search_namespace = $this->getNamespace(); + $param = $this->commandParams()[0] ?? null; + + return !empty($param) && $param === '--help'; + } + + /** + * Return the params after "php bones [command]". + * + * @param int $index Optional. Index of param. + * If NULL will be returned the whole array. + * + * @return array|string + */ + protected function commandParams($index = null) + { + $params = $this->arguments(); + + // strip the command name + array_shift($params); + + return !is_null($index) ? $params[$index] ?? null : $params; + } + + /** + * Reset the plugin name and namespace to the original values + */ + protected function resetPluginNameAndNamespace() + { + // use the current plugin name and namespace from the namespace file + $search_plugin_name = $this->getPluginName(); + $search_namespace = $this->getNamespace(); + [$plugin_name, $namespace] = $this->getDefaultPlaginNameAndNamespace(); + $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); + } + + /** + * Return the default plugin name and namespace. + */ + protected function getDefaultPlaginNameAndNamespace(): array + { + return ['WP Kirk', 'WPKirk']; + } + + /** + * Update the plugin name and namespace + * + * @param string $search_plugin_name The previous plugin name + * @param string $search_namespace The previous namespace + * @param string $plugin_name The new plugin name + * @param string $namespace The new namespace + */ + protected function setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace) + { + $mainPluginFile = $this->getMainPluginFile($plugin_name); + $currentMainPluginFile = $this->getMainPluginFile($search_plugin_name); + + // check if "index.php" exists + if (file_exists('index.php') && !file_exists($currentMainPluginFile)) { + $this->info("The file '{$currentMainPluginFile}' doesn't exists. Maybe you are updating from a < 1.5 version."); + $currentMainPluginFile = 'index.php'; + } + + rename($currentMainPluginFile, $mainPluginFile); + + // start scan everything + $files = array_filter( + array_map(function ($e) { + // exclude node_modules and bones executable + if ( + false !== strpos($e, 'node_modules') || + false !== strpos($e, 'vendor/wpbones/wpbones/src/Console/bin/bones') + ) { + return false; + } + + return $e; + }, $this->recursiveScan('*')) + ); + + // merge + $files = array_merge($files, [ + $mainPluginFile, + 'composer.json', + 'readme.txt', + ]); + + // change namespace + foreach ($files as $file) { + $this->line("🚧 Loading and process {$file}..."); + + $content = file_get_contents($file); + + // change namespace + $content = str_replace($search_namespace, $namespace, $content); + + // change slug + $content = str_replace( + $this->getPluginSlug($search_plugin_name), + $this->getPluginSlug($plugin_name), + $content + ); + + // change vars + $content = str_replace( + $this->getPluginVars($search_plugin_name), + $this->getPluginVars($plugin_name), + $content + ); + + // change id + $content = str_replace( + $this->getPluginId($search_plugin_name), + $this->getPluginId($plugin_name), + $content + ); + + // change plugin name just in main plugin file and readme.txt + if ($file === $mainPluginFile || $file === 'readme.txt') { + $content = str_replace($search_plugin_name, $plugin_name, $content); + } - if ($search_plugin_name === 'WP Kirk' && $search_namespace === 'WPKirk') { - $this->line("ℹī¸ You are renaming your plugin for the first time.\n"); - } + file_put_contents($file, $content); - $plugin_name = $args[0] ?? ''; - $namespace = $args[1] ?? ''; + $this->info("✅ {$file} content renamed completed!"); + } - // You may set just the plugin name and the namespace will be created from plugin name - if (!empty($plugin_name) && empty($namespace)) { - $namespace = str_replace(' ', '', ucwords($plugin_name)); - return [$search_plugin_name, $search_namespace, $plugin_name, $namespace]; - } + foreach (glob('localization/*') as $file) { + $newFile = str_replace( + $this->getPluginId($search_plugin_name), + $this->getPluginId($plugin_name), + $file + ); + rename($file, $newFile); + } - if (!empty($plugin_name) && !empty($namespace)) { - return [$search_plugin_name, $search_namespace, $plugin_name, $namespace]; - } + foreach (glob('resources/assets/js/*') as $file) { + $newFile = str_replace( + $this->getPluginId($search_plugin_name), + $this->getPluginId($plugin_name), + $file + ); + rename($file, $newFile); + } - $this->info('đŸšĻ ---------------------------------------------------------------------------------'); - $this->info("đŸšĻ Remember the new plugin name and namespace must not contain \"WP Kirk\" or \"WPKirk\""); - $this->info("đŸšĻ ---------------------------------------------------------------------------------\n"); + foreach (glob('resources/assets/css/*') as $file) { + $newFile = str_replace( + $this->getPluginId($search_plugin_name), + $this->getPluginId($plugin_name), + $file + ); + rename($file, $newFile); + } + + // Change also the WP Bones plugin class + $file = 'vendor/wpbones/wpbones/src/Foundation/Plugin.php'; + $content = file_get_contents($file); + $content = str_replace($currentMainPluginFile, $mainPluginFile, $content); + file_put_contents($file, $content); + + // save new plugin name and namespace + file_put_contents('namespace', "{$plugin_name},{$namespace}"); + + $this->info("👏 Rename process completed!"); + } - $plugin_name = ''; - $namespace = ''; + /** + * Return an array with all matched files from root folder. This method release the follow filters: + * + * wpdk_rglob_find_dir( true, $file ) - when find a dir + * wpdk_rglob_find_file( true, $file ) - when find a a file + * wpdk_rglob_matched( $regexp_result, $file, $match ) - after preg_match() done + * + * @brief get all matched files + * @param string $path Folder root + * @param string $match Optional. Regex to apply on file name. For example use '/^.*\.(php)$/i' to get only php + * file. Default is empty + * + * @return array + * @since 1.0.0.b4 + * + */ + protected function recursiveScan($path, $match = ''): array + { + /** + * Return an array with all matched files from root folder. + * + * @brief get all matched files + * @note Internal recursive use only + * + * @param string $path Folder root + * @param string $match Optional. Regex to apply on file name. For example use '/^.*\.(php)$/i' to get only php file + * @param array &$result Optional. Result array. Empty form first call + * + * @return array + * + * @suppress PHP0405 + */ + function _rglob($path, $match = '', &$result = []): array + { + $path = rtrim($path, '/\\') . '/'; + + $files = glob($path . '*', GLOB_MARK); + if (false !== $files) { + foreach ($files as $file) { + if (is_dir($file)) { + $continue = true; + if ($continue) { + _rglob($file, $match, $result); + } + } elseif (!empty($match)) { + $regexp_result = []; + $error = preg_match($match, $file, $regexp_result); + if (0 !== $error || false !== $error) { + if (!empty($regexp_result)) { + $result[] = $regexp_result[0]; + } + } + } else { + $result[] = $file; + } + } + + return $result; + } + } - while (empty($plugin_name)) { - $plugin_name = $this->ask('Plugin name:', $plugin_name); - $namespace = $this->ask('Namespace:', $namespace); + $result = []; - // both plugin name and namespace don't have to contains 'WP Kirk' or 'WPKirk' - if (strpos($plugin_name, 'WP Kirk') !== false || strpos($plugin_name, 'WPKirk') !== false) { - $this->error('🛑 Plugin name cannot contain "WP Kirk" or "WPKirk"'); - $plugin_name = ''; - continue; + return _rglob($path, $match, $result); } - if (strpos($namespace, 'WP Kirk') !== false || strpos($namespace, 'WPKirk') !== false) { - $this->error('🛑 Namespace cannot contain "WP Kirk" or "WPKirk"'); - $plugin_name = ''; - $namespace = ''; - continue; + /** + * Return the plugin slug. + */ + public function getPluginSlug($str = null): string + { + $str = $this->getSnakeCasePluginName($str); + + return $str . '_slug'; } - } - // You may set just the plugin name and the namespace will be created from plugin name - if (empty($namespace)) { - $namespace = str_replace(' ', '', ucwords($plugin_name)); - } + /** + * Return the snake case plugin name. + * + * @param string $str + * @return string + */ + public function getSnakeCasePluginName($str = null): string + { + $str = $this->getSanitizePluginName($str); - return [$search_plugin_name, $search_namespace, $plugin_name, $namespace]; - } + return str_replace('-', '_', $str); + } - /** - * Reset the plugin name and namespace to the original values - */ - protected function resetPluginNameAndNamespace() - { - // use the current plugin name and namespace from the namespace file - $search_plugin_name = $this->getPluginName(); - $search_namespace = $this->getNamespace(); - [$plugin_name, $namespace] = $this->getDefaultPlaginNameAndNamespace(); - $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); - } + /** + * Return the sanitized plugin name. + * + * @param string $str + * @return string + */ + public function getSanitizePluginName($str = null): string + { + if (is_null($str)) { + $str = $this->getPluginName(); + } - /** - * Update the plugin name and namespace after a install new package - */ - protected function updatePluginNameAndNamespace() - { - // use the current plugin name and namespace from the namespace file - $plugin_name = $this->getPluginName(); - $namespace = $this->getNamespace(); - [$search_plugin_name, $search_namespace] = $this->getDefaultPlaginNameAndNamespace(); - $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); - } + return $this->sanitize($str); + } - /** - * Update the plugin name and namespace - * - * @param string $search_plugin_name The previous plugin name - * @param string $search_namespace The previous namespace - * @param string $plugin_name The new plugin name - * @param string $namespace The new namespace - */ - protected function setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace) - { - // start scan everything - $files = array_filter( - array_map(function ($e) { - // exclude node_modules and bones executable - if ( - false !== strpos($e, 'node_modules') || - false !== strpos($e, 'vendor/wpbones/wpbones/src/Console/bin/bones') - ) { - return false; - } - - return $e; - }, $this->recursiveScan('*')) - ); - - // merge - $files = array_merge($files, [ - 'index.php', - 'composer.json', - 'readme.txt', - ]); - - // change namespace - foreach ($files as $file) { - $this->line("🚧 Loading and process {$file}..."); - - $content = file_get_contents($file); - - // change namespace - $content = str_replace($search_namespace, $namespace, $content); - - // change slug - $content = str_replace( - $this->getPluginSlug($search_plugin_name), - $this->getPluginSlug($plugin_name), - $content - ); - - // change vars - $content = str_replace( - $this->getPluginVars($search_plugin_name), - $this->getPluginVars($plugin_name), - $content - ); - - // change id - $content = str_replace( - $this->getPluginId($search_plugin_name), - $this->getPluginId($plugin_name), - $content - ); - - // change plugin name just in index.php and readme.txt - if ($file === 'index.php' || $file === 'readme.txt') { - $content = str_replace($search_plugin_name, $plugin_name, $content); - } - - file_put_contents($file, $content); - - $this->info("✅ Renamed completed!"); - } - - foreach (glob('localization/*') as $file) { - $newFile = str_replace( - $this->getPluginId($search_plugin_name), - $this->getPluginId($plugin_name), - $file - ); - rename($file, $newFile); - } - - foreach (glob('resources/assets/js/*') as $file) { - $newFile = str_replace( - $this->getPluginId($search_plugin_name), - $this->getPluginId($plugin_name), - $file - ); - rename($file, $newFile); - } - - foreach (glob('resources/assets/css/*') as $file) { - $newFile = str_replace( - $this->getPluginId($search_plugin_name), - $this->getPluginId($plugin_name), - $file - ); - rename($file, $newFile); - } - - // save new plugin name and namespace - file_put_contents('namespace', "{$plugin_name},{$namespace}"); - } + /** + * Return a kebalized version of the string + * + * @param string $title + */ + protected function sanitize($title): string + { + $title = strip_tags($title); + // Preserve escaped octets. + $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title); + // Remove percent signs that are not part of an octet. + $title = str_replace('%', '', $title); + // Restore octets. + $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title); + + $title = strtolower($title); + + $title = preg_replace('/&.+?;/', '', $title); // kill entities + $title = str_replace('.', '-', $title); + + $title = preg_replace('/[^%a-z0-9 _-]/', '', $title); + $title = preg_replace('/\s+/', '-', $title); + $title = preg_replace('|-+|', '-', $title); + + return trim($title, '-'); + } - /** - * Commodity function to check if help has been requested. - * - * @param string $str Optional. Command to check. - * - * @return bool - */ - protected function isHelp($str = null): bool - { - if (!is_null($str)) { - return empty($str) || $str === '--help'; - } + /** + * Return the plugin vars. + * + * @param string $str + * @return string + */ + public function getPluginVars($str = null): string + { + $str = $this->getSnakeCasePluginName($str); - $param = $this->commandParams()[0] ?? null; + return $str . '_vars'; + } - return !empty($param) && $param === '--help'; - } + /** + * Return the plugin id used for css, js, less and files. + * Currently, it's the sanitized plugin name. + * + * @param string|null $str + * + * @return string + */ + public function getPluginId(string $str = null): string + { + return $this->getSanitizePluginName($str); + } - /** - * Return the params after "php bones [command]". - * - * @param int $index Optional. Index of param. - * If NULL will be returned the whole array. - * - * @return array|string - */ - protected function commandParams($index = null) - { - $params = $this->arguments(); + /** + * Update the plugin name and namespace after a install new package + */ + protected function updatePluginNameAndNamespace() + { + // use the current plugin name and namespace from the namespace file + $plugin_name = $this->getPluginName(); + $namespace = $this->getNamespace(); + [$search_plugin_name, $search_namespace] = $this->getDefaultPlaginNameAndNamespace(); + $this->setPluginNameAndNamespace($search_plugin_name, $search_namespace, $plugin_name, $namespace); + } - // strip the command name - array_shift($params); + /** + * Get the plugin name and namespace from args or ask them from the console + * + * @param array $args The arguments from the console. The first argument is the plugin name and the second is the namespace + * + */ + protected function getAskPluginNameAndNamespace($args): array + { + // Get the current plugin name and namespace + $search_plugin_name = $this->getPluginName(); + $search_namespace = $this->getNamespace(); + + if ($search_plugin_name === 'WP Kirk' && $search_namespace === 'WPKirk') { + $this->line("ℹī¸ You are renaming your plugin for the first time.\n"); + } - return !is_null($index) ? $params[$index] ?? null : $params; - } + $plugin_name = $args[0] ?? ''; + $namespace = $args[1] ?? ''; - /** - * Get input from console - * - * @param string $str The question to ask - * @param string $default The default value - */ - protected function ask($str, $default = ''): string - { - echo "\n\e[38;5;33m$str" . - (empty($default) ? '' : " (default: {$default})") . - "\e[0m "; + // You may set just the plugin name and the namespace will be created from plugin name + if (!empty($plugin_name) && empty($namespace)) { + $namespace = str_replace(' ', '', ucwords($plugin_name)); + return [$search_plugin_name, $search_namespace, $plugin_name, $namespace]; + } - $handle = fopen('php://stdin', 'r'); - $line = fgets($handle); + if (!empty($plugin_name) && !empty($namespace)) { + return [$search_plugin_name, $search_namespace, $plugin_name, $namespace]; + } - fclose($handle); + $this->info('đŸšĻ ---------------------------------------------------------------------------------'); + $this->info("đŸšĻ Remember the new plugin name and namespace must not contain \"WP Kirk\" or \"WPKirk\""); + $this->info("đŸšĻ ---------------------------------------------------------------------------------\n"); - $line = trim($line, " \n\r"); + $plugin_name = ''; + $namespace = ''; - return $line ?: $default; - } + while (empty($plugin_name)) { + $plugin_name = $this->ask('Plugin name:', $plugin_name); + $namespace = $this->ask('Namespace:', $namespace); - /** - * Return the defaulr plugin name and namespace. - */ - protected function getDefaultPlaginNameAndNamespace(): array - { - return ['WP Kirk', 'WPKirk']; - } + // both plugin name and namespace don't have to contains 'WP Kirk' or 'WPKirk' + if (strpos($plugin_name, 'WP Kirk') !== false || strpos($plugin_name, 'WPKirk') !== false) { + $this->error('🛑 Plugin name cannot contain "WP Kirk" or "WPKirk"'); + $plugin_name = ''; + continue; + } - /** - * Return an array with all matched files from root folder. This method release the follow filters: - * - * wpdk_rglob_find_dir( true, $file ) - when find a dir - * wpdk_rglob_find_file( true, $file ) - when find a a file - * wpdk_rglob_matched( $regexp_result, $file, $match ) - after preg_match() done - * - * @brief get all matched files - * @param string $path Folder root - * @param string $match Optional. Regex to apply on file name. For example use '/^.*\.(php)$/i' to get only php - * file. Default is empty - * - * @return array - * @since 1.0.0.b4 - * - */ - protected function recursiveScan($path, $match = ''): array - { - /** - * Return an array with all matched files from root folder. - * - * @brief get all matched files - * @note Internal recursive use only - * - * @param string $path Folder root - * @param string $match Optional. Regex to apply on file name. For example use '/^.*\.(php)$/i' to get only php file - * @param array &$result Optional. Result array. Empty form first call - * - * @return array - * - * @suppress PHP0405 - */ - function _rglob($path, $match = '', &$result = []): array - { - $path = rtrim($path, '/\\') . '/'; - - $files = glob($path . '*', GLOB_MARK); - if (false !== $files) { - foreach ($files as $file) { - if (is_dir($file)) { - $continue = true; - if ($continue) { - _rglob($file, $match, $result); - } - } elseif (!empty($match)) { - $regexp_result = []; - $error = preg_match($match, $file, $regexp_result); - if (0 !== $error || false !== $error) { - if (!empty($regexp_result)) { - $result[] = $regexp_result[0]; + if (strpos($namespace, 'WP Kirk') !== false || strpos($namespace, 'WPKirk') !== false) { + $this->error('🛑 Namespace cannot contain "WP Kirk" or "WPKirk"'); + $plugin_name = ''; + $namespace = ''; + continue; } - } - } else { - $result[] = $file; } - } - return $result; + // You may set just the plugin name and the namespace will be created from plugin name + if (empty($namespace)) { + $namespace = str_replace(' ', '', ucwords($plugin_name)); + } + + $mainPluginFile = $this->getMainPluginFile($plugin_name); + + return [$search_plugin_name, $search_namespace, $plugin_name, $namespace, $mainPluginFile]; } - } - $result = []; + /* + |-------------------------------------------------------------------------- + | Internal useful function + |-------------------------------------------------------------------------- + | + | Here you will find all internal methods + | + */ - return _rglob($path, $match, $result); - } + /** + * Get input from console + * + * @param string $str The question to ask + * @param string $default The default value + */ + protected function ask($str, $default = ''): string + { + echo "\n\e[38;5;33m$str" . + (empty($default) ? '' : " (default: {$default})") . + "\e[0m "; - /** - * Return the plugin slug. - */ - public function getPluginSlug($str = null): string - { - $str = $this->getSnakeCasePluginName($str); + $handle = fopen('php://stdin', 'r'); + $line = fgets($handle); - return $str . '_slug'; - } + fclose($handle); - /** - * Return the snake case plugin name. - * - * @param string $str - * @return string - */ - public function getSnakeCasePluginName($str = null): string - { - $str = $this->getSanitizePluginName($str); + $line = trim($line, " \n\r"); - return str_replace('-', '_', $str); - } + return $line ?: $default; + } - /** - * Return the sanitized plugin name. - * - * @param string $str - * @return string - */ - public function getSanitizePluginName($str = null): string - { - if (is_null($str)) { - $str = $this->getPluginName(); - } + /** + * Commodity to display an error message in the console. + * + * @param string $str The message to display. + */ + protected function error($str) + { + echo "\033[41m\n"; + echo "\033[41;255m" . $str . "\n"; + echo "\033[0m\n"; + } - return $this->sanitize($str); - } + /** + * Execute composer install + */ + protected function install() + { + if ($this->isHelp()) { + $this->line("Will run the composer install\n"); + $this->info('Usage:'); + $this->line(' php bones install'); + exit(); + } + $this->line(`composer install`); + } - /* - |-------------------------------------------------------------------------- - | Internal useful function - |-------------------------------------------------------------------------- - | - | Here you will find all internal methods - | - */ + /** + * Execute composer update + */ + protected function update() + { + if ($this->isHelp()) { + $this->line( + "Will run the composer update. Useful if there is a new version of WP Bones\n" + ); + $this->info('Usage:'); + $this->line(' php bones update'); + exit(); + } + // delete the current vendor/wpbones/wpbones folder + $this->deleteDirectory('vendor/wpbones/wpbones'); - /** - * Return a kebalized version of the string - * - * @param string $title - */ - protected function sanitize($title): string - { - $title = strip_tags($title); - // Preserve escaped octets. - $title = preg_replace('|%([a-fA-F0-9][a-fA-F0-9])|', '---$1---', $title); - // Remove percent signs that are not part of an octet. - $title = str_replace('%', '', $title); - // Restore octets. - $title = preg_replace('|---([a-fA-F0-9][a-fA-F0-9])---|', '%$1', $title); + // update composer module + $this->line(`composer update`); + } - $title = strtolower($title); + /** + * Delete a whole folder + * + * @param string $path The path to the folder to delete + */ + public function deleteDirectory($path) + { + $path = rtrim($path, '/'); + + array_map(function ($file) { + if (is_dir($file)) { + $this->deleteDirectory($file); + } else { + @unlink($file); + } + }, glob("{$path}/" . '{,.}[!.,!..]*', GLOB_MARK | GLOB_BRACE)); - $title = preg_replace('/&.+?;/', '', $title); // kill entities - $title = str_replace('.', '-', $title); + @rmdir("{$path}"); + } - $title = preg_replace('/[^%a-z0-9 _-]/', '', $title); - $title = preg_replace('/\s+/', '-', $title); - $title = preg_replace('|-+|', '-', $title); + /** + * Run subtask. Handle the php bones commands. + * + */ + protected function handle() + { + // deploy + if ($this->isCommand('deploy')) { + $this->deploy($this->commandParams()); + } // Optimize + elseif ($this->isCommand('optimize')) { + $this->optimize(); + } // Tinker + elseif ($this->isCommand('tinker')) { + $this->tinker(); + } // Require + elseif ($this->isCommand('require')) { + $this->requirePackage($this->commandParams(0)); + } // Version + elseif ($this->isCommand('version')) { + $this->version($this->commandParams()); + } // migrate:create {table_name} + elseif ($this->isCommand('migrate:create')) { + $this->createMigrate($this->commandParams(0)); + } // make:controller {controller_name} + elseif ($this->isCommand('make:controller')) { + $this->createController($this->commandParams(0)); + } // make:console {command_name} + elseif ($this->isCommand('make:console')) { + $this->createCommand($this->commandParams(0)); + } // make:cpt {className} + elseif ($this->isCommand('make:cpt')) { + $this->createCustomPostType($this->commandParams(0)); + } // make:shortcode {className} + elseif ($this->isCommand('make:shortcode')) { + $this->createShortcode($this->commandParams(0)); + } // make:provider {className} + elseif ($this->isCommand('make:provider')) { + $this->createProvider($this->commandParams(0)); + } // make:ajax {className} + elseif ($this->isCommand('make:ajax')) { + $this->createAjax($this->commandParams(0)); + } // make:ctt {className} + elseif ($this->isCommand('make:ctt')) { + $this->createCustomTaxonomyType($this->commandParams(0)); + } // make:widget {className} + elseif ($this->isCommand('make:widget')) { + $this->createWidget($this->commandParams(0)); + } // make:model {className} + elseif ($this->isCommand('make:model')) { + $this->createModel($this->commandParams(0)); + } // make:eloquent-model {className} + elseif ($this->isCommand('make:eloquent-model')) { + $this->createEloquentModel($this->commandParams(0)); + } // make:api {className} + elseif ($this->isCommand('make:api')) { + $this->createAPIController($this->commandParams(0)); + } // else... + else { + $extended = false; + + if ($this->kernel) { + $extended = $this->kernel->handle($this->arguments()); + } - return trim($title, '-'); - } + if (!$extended) { + $this->info("\nUnknown command! Use --help for commands list\n"); + } + } + } - /** - * Return the plugin vars. - * - * @param string $str - * @return string - */ - public function getPluginVars($str = null): string - { - $str = $this->getSnakeCasePluginName($str); + /* + |-------------------------------------------------------------------------- + | Public task + |-------------------------------------------------------------------------- + | + | Here you will find all tasks that a user can run from console. + | + */ - return $str . '_vars'; - } + /** + * Create a deployment version of the plugin + * + * @param string $path The path to the deployment version of the plugin + */ + protected function deploy($argv) + { + + $path = $argv[0] !== '--wp' ? $argv[0] : ''; + $index = $argv[0] !== '--wp' ? 1 : 0; + $is_wp_org = $argv[$index] === '--wp'; + + $this->info("\nStarting deploy ¯\_(ツ)_/¯\n"); + + $path = rtrim($path, '/'); + + if (empty($path)) { + $path = $this->ask('Enter the complete path of deploy:'); + } elseif ('--help' === $path) { + $this->line("\nUsage:"); + $this->info(" deploy \n"); + $this->line('Arguments:'); + $this->info(" path\tThe complete path of deploy."); + $this->info(" [--wp]\tWe are going to release this plugin in the WordPress.org public repository."); + exit(0); + } - /** - * Return the plugin id used for css, js, less and files. - * Currently, it's the sanitized plugin name. - * - * @param string|null $str - * - * @return string - */ - public function getPluginId(string $str = null): string - { - return $this->getSanitizePluginName($str); - } + if (!empty($path)) { - /** - * Execute composer install - */ - protected function install() - { - if ($this->isHelp()) { - $this->line("Will run the composer install\n"); - $this->info('Usage:'); - $this->line(' php bones install'); - exit(); - } - $this->line(`composer install`); - } + $dontSkipWhenDeploy = [ + '/resources/assets', + '/composer.json', + '/composer.lock', + ]; - /** - * Execute composer update - */ - protected function update() - { - if ($this->isHelp()) { - $this->line( - "Will run the composer update. Useful if there is a new version of WP Bones\n" - ); - $this->info('Usage:'); - $this->line(' php bones update'); - exit(); - } - // delete the current vendor/wpbones/wpbones folder - $this->deleteDirectory('vendor/wpbones/wpbones'); + if ($is_wp_org) { + $this->info("\nđŸšĻ You are going to release this plugin in the WordPress.org public repository"); + $this->line("\n→ In this case some files won't be skipped during the deployment."); + $this->line("→ The files that won't be skipped are:\n\n" . implode("\n", $dontSkipWhenDeploy) . "\n\n"); + } - // update composer module - $this->line(`composer update`); - } + // alternative method to customize the deployment + @include 'deploy.php'; - /** - * Run subtask. Handle the php bones commands. - * - */ - protected function handle() - { - // deploy - if ($this->isCommand('deploy')) { - $this->deploy($this->arguments(1)); - } - // Optimize - elseif ($this->isCommand('optimize')) { - $this->optimize(); - } - // Tinker - elseif ($this->isCommand('tinker')) { - $this->tinker(); - } - // Require - elseif ($this->isCommand('require')) { - $this->requirePackage($this->commandParams(0)); - } - // Version - elseif ($this->isCommand('version')) { - $this->version($this->commandParams()); - } - // migrate:create {table_name} - elseif ($this->isCommand('migrate:create')) { - $this->createMigrate($this->commandParams(0)); - } - // make:controller {controller_name} - elseif ($this->isCommand('make:controller')) { - $this->createController($this->commandParams(0)); - } - // make:console {command_name} - elseif ($this->isCommand('make:console')) { - $this->createCommand($this->commandParams(0)); - } - // make:cpt {className} - elseif ($this->isCommand('make:cpt')) { - $this->createCustomPostType($this->commandParams(0)); - } - // make:shortcode {className} - elseif ($this->isCommand('make:shortcode')) { - $this->createShortcode($this->commandParams(0)); - } - // make:provider {className} - elseif ($this->isCommand('make:provider')) { - $this->createProvider($this->commandParams(0)); - } - // make:ajax {className} - elseif ($this->isCommand('make:ajax')) { - $this->createAjax($this->commandParams(0)); - } - // make:ctt {className} - elseif ($this->isCommand('make:ctt')) { - $this->createCustomTaxonomyType($this->commandParams(0)); - } - // make:widget {className} - elseif ($this->isCommand('make:widget')) { - $this->createWidget($this->commandParams(0)); - } - // make:model {className} - elseif ($this->isCommand('make:model')) { - $this->createModel($this->commandParams(0)); - } - // make:eloquent-model {className} - elseif ($this->isCommand('make:eloquent-model')) { - $this->createEloquentModel($this->commandParams(0)); - } - // make:api {className} - elseif ($this->isCommand('make:api')) { - $this->createAPIController($this->commandParams(0)); - } - // else... - else { - $extended = false; - - if ($this->kernel) { - $extended = $this->kernel->handle($this->arguments()); - } - - if (!$extended) { - $this->info("\nUnknown command! Use --help for commands list\n"); - } - } - } + do_action('wpbones_console_deploy_start', $this, $path); - /* - |-------------------------------------------------------------------------- - | Public task - |-------------------------------------------------------------------------- - | - | Here you will find all tasks that a user can run from console. - | - */ + // first delete previous path + $this->info("🕐 Delete folder {$path}"); + $this->deleteDirectory($path); + $this->info("\033[1A👍"); - /** - * Create a deployment version of the plugin - * - * @param string $path The path to the deployment version of the plugin - */ - protected function deploy($path) - { - $this->info("\nStarting deploy ¯\_(ツ)_/¯\n"); + do_action('wpbones_console_deploy_before_build_assets', $this, $path); - $path = rtrim($path, '/'); + $packageManager = $this->getAvailablePackageManager(); - if (empty($path)) { - $path = $this->ask('Enter the complete path of deploy:'); - } elseif ('--help' === $path) { - $this->line("\nUsage:"); - $this->info(" deploy \n"); - $this->line('Arguments:'); - $this->info(" path\tThe complete path of deploy."); - exit(0); - } + if ($packageManager) { - if (!empty($path)) { - // alternative method to customize the deployment - @include 'deploy.php'; + $this->info("✅ Found '$packageManager' as package manager"); - do_action('wpbones_console_deploy_start', $this, $path); + $answer = $this->ask("Do you want to run '$packageManager run build' to build assets? (y/n)", 'y'); - // first delete previous path - $this->info("🕐 Delete folder {$path}"); - $this->deleteDirectory($path); - $this->info("\033[1A👍"); + if (strtolower($answer) === 'y') { + $this->info("đŸ“Ļ Build for production by using '{$packageManager} run build'"); + shell_exec("{$packageManager} run build"); + $this->info("✅ Built assets successfully"); + do_action('wpbones_console_deploy_after_build_assets', $this, $path); + } else { + $answer = $this->ask("Enter the package manager to build assets (press RETURN to skip the build)", ''); + if (empty($answer)) { + $this->info('⏭ī¸Ž Skip build assets'); + } else { + $this->info("đŸ“Ļ Build for production by using '{$answer} run build'"); + shell_exec("{$answer} run build"); + $this->info("✅ Built assets successfully"); + do_action('wpbones_console_deploy_after_build_assets', $this, $path); + } + } + } else { + $this->info("🛑 No package manager found. The build assets will be skipped"); + } + + // files and folders to skip + $this->skipWhenDeploy = [ + '/.git', + '/.cache', + '/assets', + '/.gitignore', + '/.gitkeep', + '/.DS_Store', + '/.babelrc', + '/node_modules', + '/bones', + '/vendor/wpbones/wpbones/src/Console/stubs', + '/vendor/wpbones/wpbones/src/Console/bin', + '/deploy.php', + '/namespace', + '/gulpfile.js', + '/package.json', + '/package-lock.json', + '/yarn.lock', + '/pnpm-lock.yaml', + '/README.md', + '/webpack.mix.js', + '/webpack.config.js', + '/phpcs.xml.dist', + '/mix-manifest.json', + '/release.sh', + ]; + + // The new strict rules require that the composer must also be released to publish the plugin in the WordPress.org repository. + if (!$is_wp_org) { + $this->skipWhenDeploy = array_merge($this->skipWhenDeploy, $dontSkipWhenDeploy); + } - do_action('wpbones_console_deploy_before_build_assets', $this, $path); - $packageManager = $this->getAvailablePackageManager(); + /** + * Filter the list of files and folders to skip during the deployment. + * + * @param array $array The files and folders are relative to the root of plugin. + */ + $this->skipWhenDeploy = apply_filters( + 'wpbones_console_deploy_skip_folders', + $this->skipWhenDeploy + ); + + $this->rootDeploy = __DIR__; + + $this->info("🚧 Copying to {$path}"); + $this->xcopy(__DIR__, $path); + $this->info("✅ Copy completed"); + + /** + * Fires when the console deploy is completed. + * + * @param mixed $bones Bones command instance. + * @param string $path The deployed path. + */ + do_action('wpbones_console_deploy_completed', $this, $path); + + $this->info("\n\e[5m👏 Deploy completed!\e[0m"); + $this->info("\n🚀 You can now deploy the plugin from the path: {$path}\n"); + } + } + + + /** + * Returns the available package manager + * + * @return string|null The name of the available package manager (yarn, npm, pnpm, bun) or null if none is available. + */ + protected function getAvailablePackageManager() + { + $packageManagers = ['yarn', 'npm', 'pnpm', 'bun']; + + foreach ($packageManagers as $manager) { + if ($this->isCommandAvailable($manager)) { + return $manager; + } + } - if ($packageManager) { + return null; + } - $this->info("✅ Found '$packageManager' as package manager"); + /** + * Return true if the command is available in the system. + * + * @return string + */ + protected function isCommandAvailable($command) + { + $whereCommand = (PHP_OS_FAMILY === 'Windows') ? 'where' : 'command -v'; + $output = shell_exec("$whereCommand $command"); + return !empty($output); + } - $answer = $this->ask("Do you want to run '$packageManager run build' to build assets? (y/n)", 'y'); + /** + * Copy a whole folder. Used by deploy() + * + * @param string $source The source path + * @param string $dest The target path + * @param int $permissions The permissions to set + * + * @return bool + */ + protected function xcopy($source, $dest, $permissions = 0755): bool + { + // Check for symlinks + if (is_link($source)) { + return symlink(readlink($source), $dest); + } - if (strtolower($answer) === 'y') { - $this->info("đŸ“Ļ Build for production by using '{$packageManager} run build'"); - shell_exec("{$packageManager} run build"); - $this->info("✅ Built assets successfully"); - do_action('wpbones_console_deploy_after_build_assets', $this, $path); - } else { - $answer = $this->ask("Enter the package manager to build assets (press RETURN to skip the build)", ''); - if (empty($answer)) { - $this->info('⏭ī¸Ž Skip build assets'); - } else { - $this->info("đŸ“Ļ Build for production by using '{$answer} run build'"); - shell_exec("{$answer} run build"); - $this->info("✅ Built assets successfully"); - do_action('wpbones_console_deploy_after_build_assets', $this, $path); - } - } - } else { - $this->info("🛑 No package manager found. The build assets will be skipped"); - } - - // files and folders to skip - $this->skipWhenDeploy = [ - '/.git', - '/.cache', - '/assets', - '/.gitignore', - '/.gitkeep', - '/.DS_Store', - '/.babelrc', - '/node_modules', - '/bones', - '/vendor/wpbones/wpbones/src/Console/stubs', - '/vendor/wpbones/wpbones/src/Console/bin', - '/resources/assets', - '/deploy.php', - '/composer.json', - '/composer.lock', - '/namespace', - '/gulpfile.js', - '/package.json', - '/package-lock.json', - '/yarn.lock', - '/pnpm-lock.yaml', - '/README.md', - '/webpack.mix.js', - '/webpack.config.js', - '/phpcs.xml.dist', - '/mix-manifest.json', - '/release.sh', - ]; - - /** - * Filter the list of files and folders to skip during the deployment. - * - * @param array $array The files and folders are relative to the root of plugin. - */ - $this->skipWhenDeploy = apply_filters( - 'wpbones_console_deploy_skip_folders', - $this->skipWhenDeploy - ); - - $this->rootDeploy = __DIR__; - - $this->info("🚧 Copying to {$path}"); - $this->xcopy(__DIR__, $path); - $this->info("✅ Copy completed"); - - /** - * Fires when the console deploy is completed. - * - * @param mixed $bones Bones command instance. - * @param string $path The deployed path. - */ - do_action('wpbones_console_deploy_completed', $this, $path); - - $this->info("\n\e[5m👏 Deploy completed!\e[0m"); - $this->info("\n🚀 You can now deploy the plugin from the path: {$path}\n"); - } - } + // Simple copy for a file + if (is_file($source)) { + // if the file starts with "." or is in the skip list + // we don't copy it - /** - * Delete a whole folder - * - * @param string $path The path to the folder to delete - */ - public function deleteDirectory($path) - { - $path = rtrim($path, '/'); + if (strpos(basename($source), '.') === 0 || $this->skip($source)) { + return false; + } + return copy($source, $dest); + } - array_map(function ($file) { - if (is_dir($file)) { - $this->deleteDirectory($file); - } else { - @unlink($file); - } - }, glob("{$path}/" . '{,.}[!.,!..]*', GLOB_MARK | GLOB_BRACE)); + // Make destination directory + if (!is_dir($dest)) { + mkdir($dest, $permissions); + } - @rmdir("{$path}"); - } + // Loop through the folder + $dir = dir($source); + + while (false !== ($entry = $dir->read())) { + // files and folder to skip + if ( + $entry === '.' || + $entry === '..' || + strpos($entry, '.') === 0 || + $this->skip("{$source}/{$entry}") + ) { + continue; + } - /** - * Copy a whole folder. Used by deploy() - * - * @param string $source The source path - * @param string $dest The target path - * @param int $permissions The permissions to set - * - * @return bool - */ - protected function xcopy($source, $dest, $permissions = 0755): bool - { - // Check for symlinks - if (is_link($source)) { - return symlink(readlink($source), $dest); - } + // Deep copy directories + $this->xcopy("{$source}/{$entry}", "{$dest}/{$entry}", $permissions); + } - // Simple copy for a file - if (is_file($source)) { - // if the file starts with "." or is in the skip list - // we don't copy it + // Clean up + $dir->close(); - if (strpos(basename($source), '.') === 0 || $this->skip($source)) { - return false; + return true; } - return copy($source, $dest); - } - - // Make destination directory - if (!is_dir($dest)) { - mkdir($dest, $permissions); - } - // Loop through the folder - $dir = dir($source); + /** + * Used to skip some files and folders during the deployment + * + * @param string $value The file or folder to skip + * + * @return bool + */ + protected function skip($value): bool + { + $single = str_replace($this->rootDeploy, '', $value); - while (false !== ($entry = $dir->read())) { - // files and folder to skip - if ( - $entry === '.' || - $entry === '..' || - strpos($entry, '.') === 0 || - $this->skip("{$source}/{$entry}") - ) { - continue; + return in_array($single, $this->skipWhenDeploy); } - // Deep copy directories - $this->xcopy("{$source}/{$entry}", "{$dest}/{$entry}", $permissions); - } + /** + * Alias composer dump-autoload + */ + protected function optimize() + { + $this->line(`composer dump-autoload -o`); + } - // Clean up - $dir->close(); + /** + * Start a Tinker emulation + */ + protected function tinker() + { + $eval = $this->ask('>>>'); - return true; - } + try { + if ($eval == 'exit') { + exit(); + } - /** - * Used to skip some files and folders during the deployment - * - * @param string $value The file or folder to skip - * - * @return bool - */ - protected function skip($value): bool - { - $single = str_replace($this->rootDeploy, '', $value); + if (substr($eval, -1) != ';') { + $eval .= ';'; + } - return in_array($single, $this->skipWhenDeploy); - } + $this->line(eval($eval)); + } catch (Exception $e) { + $this->info(eval($e->getMessage())); + } finally { + $this->tinker(); + } + } - /** - * Alias composer dump-autoload - */ - protected function optimize() - { - $this->line(`composer dump-autoload -o`); - } + /** + * Install a new composer package + * + * @param string $package The composer package to install + */ + protected function requirePackage($package) + { + if ($this->isHelp($package)) { + $this->info('Use php bones require '); + exit(); + } - /** - * Start a Tinker emulation - */ - protected function tinker() - { - $eval = $this->ask('>>>'); + $this->line(`composer require {$package}`); - try { - if ($eval == 'exit') { - exit(); + // rename as it is + $this->rename(['--update']); } - if (substr($eval, -1) != ';') { - $eval .= ';'; - } + /** + * Handle the plugin version by SemVer. + * As you know we have to handle two different plugin version: the first one is the plugin version, the second one + * is the readme.txt version. This means that we are going to load and check both files. We have to check if the + * version are the same as well. + * + * @throws InvalidVersionException + */ + protected function version($argv) + { + $version_number_from_index_php = ''; + $version_number_from_readme_txt = ''; + $stable_tag_version_from_readme_txt = ''; + $version_string_from_index_php = ''; + + $mainPluginFilename = $this->getMainPluginFile(); + + // get all contents + $readme_txt_content = file_get_contents('readme.txt'); + $index_php_content = file_get_contents($mainPluginFilename); + + // parse the readme.txt version + $lines = explode("\n", $readme_txt_content); + foreach ($lines as $line) { + if (preg_match('/^[ \t\/*#@]*Stable tag:\s*(.*)$/i', $line, $matches)) { + /** + * The version is in the format of: Stable tag: 1.0.0 + */ + $stable_tag_version_from_readme_txt = $matches[0]; + + /** + * The version is in the format of: 1.0.0 or 1.0.0-beta.1 or 1.0.0-alpha.1 or 1.0.0-rc.1 + */ + $version_number_from_readme_txt = $matches[1]; + + $this->line( + "\nreadme.txt > $version_number_from_readme_txt ($stable_tag_version_from_readme_txt)" + ); + break; + } + } - $this->line(eval($eval)); - } catch (Exception $e) { - $this->info(eval($e->getMessage())); - } finally { - $this->tinker(); - } - } + // parse the $mainPluginFilename version + $lines = explode("\n", $index_php_content); + foreach ($lines as $line) { + // get the plugin version for WordPress comments + if (preg_match('/^[ \t\/*#@]*Version:\s*(.*)$/i', $line, $matches)) { + /** + * The version is in the format of: * Version: 1.0.0 + */ + $version_string_from_index_php = $matches[0]; + + /** + * The version is in the format of: 1.0.0 + */ + $version_number_from_index_php = $matches[1]; + + $this->line( + "$mainPluginFilename > {$version_number_from_index_php} ($version_string_from_index_php)" + ); + break; + } + } - /** - * Install a new composer package - * - * @param string $package The composer package to install - */ - protected function requirePackage($package) - { - if ($this->isHelp($package)) { - $this->info('Use php bones require '); - exit(); - } + if ($version_number_from_index_php != $version_number_from_readme_txt) { + $this->error( + "\nWARNING:\n\nThe version in readme.txt and $mainPluginFilename are different." + ); + } - $this->line(`composer require {$package}`); + if (!isset($argv[0]) || empty($argv[0])) { + $version = $this->ask('Enter new version of your plugin:'); + } elseif ($this->isHelp()) { + $this->line("\nUsage:"); + $this->info(" version [plugin version]\n"); + $this->line('Arguments:'); + $this->info( + " [plugin version]\t\tThe version of plugin. Examples: '2.0', 'v1.2', '1.2.0-rc.40', 'v1-beta.4'" + ); + $this->info(" [--major]\t\t\tIncrement the .y.z of plugin."); + $this->info(" [--minor]\t\t\tIncrement the x..z of plugin."); + $this->info(" [--patch]\t\t\tIncrement the x.y. of plugin."); + $this->info( + " [--pre-patch] \tIncrement the x.y.-. of plugin." + ); + $this->info( + " [--pre-minor] \tIncrement the x..z-. of plugin." + ); + $this->info( + " [--pre-major] \tIncrement the .y.z-. of plugin.\n" + ); + exit(0); + } elseif (isset($argv[0]) && '--patch' === $argv[0]) { + $version = semver($version_number_from_index_php)->incrementPatch(); + } elseif (isset($argv[0]) && '--minor' === $argv[0]) { + $version = semver($version_number_from_index_php)->incrementMinor(); + } elseif (isset($argv[0]) && '--major' === $argv[0]) { + $version = semver($version_number_from_index_php)->incrementMajor(); + } elseif ( + isset($argv[0]) && + in_array($argv[0], ['--pre-patch', '--pre-major', '--pre-minor']) + ) { + $prefix = $argv[1] ?? 'rc'; + + $methods = [ + '--pre-patch' => 'incrementPatch', + '--pre-major' => 'incrementMajor', + '--pre-minor' => 'incrementMinor', + ]; + // if $version_number_from_index_php is not a pre-release version + if (strpos($version_number_from_index_php, $prefix) === false) { + $prerelease = semver($version_number_from_index_php)->{$methods[$argv[0]]}(); + $version = semver($prerelease) + ->setPreRelease($prefix) + ->incrementPreRelease(); + } else { + $version = semver( + $version_number_from_index_php + )->incrementPreRelease(); + } + } else { + $version = trim($argv[0]); + } - // rename as it is - $this->rename(['--update']); - } + if ($version === '') { + $version = semver($version_number_from_index_php)->incrementPatch(); + } - /** - * Handle the plugin version by SemVer. - * As you know we have to handle two different plugin version: the first one is the plugin version, the second one - * is the readme.txt version. This means that we are going to load and check both files. We have to check if the - * version are the same as well. - * - * @throws \Bones\SemVer\Exceptions\InvalidVersionException - */ - protected function version($argv) - { - $version_number_from_index_php = ''; - $version_number_from_readme_txt = ''; - $stable_tag_version_from_readme_txt = ''; - $version_string_from_index_php = ''; - - // get all contents - $readme_txt_content = file_get_contents('readme.txt'); - $index_php_content = file_get_contents('index.php'); - - // parse the readme.txt version - $lines = explode("\n", $readme_txt_content); - foreach ($lines as $line) { - if (preg_match('/^[ \t\/*#@]*Stable tag:\s*(.*)$/i', $line, $matches)) { - /** - * The version is in the format of: Stable tag: 1.0.0 - */ - $stable_tag_version_from_readme_txt = $matches[0]; - - /** - * The version is in the format of: 1.0.0 or 1.0.0-beta.1 or 1.0.0-alpha.1 or 1.0.0-rc.1 - */ - $version_number_from_readme_txt = $matches[1]; - - $this->line( - "\nreadme.txt > $version_number_from_readme_txt ($stable_tag_version_from_readme_txt)" - ); - break; - } - } - - // parse the index.php version - $lines = explode("\n", $index_php_content); - foreach ($lines as $line) { - // get the plugin version for WordPress comments - if (preg_match('/^[ \t\/*#@]*Version:\s*(.*)$/i', $line, $matches)) { - /** - * The version is in the format of: * Version: 1.0.0 - */ - $version_string_from_index_php = $matches[0]; - - /** - * The version is in the format of: 1.0.0 - */ - $version_number_from_index_php = $matches[1]; - - $this->line( - "index.php > {$version_number_from_index_php} ($version_string_from_index_php)" - ); - break; - } - } - - if ($version_number_from_index_php != $version_number_from_readme_txt) { - $this->error( - "\nWARNING:\n\nThe version in readme.txt and index.php are different." - ); - } - - if (!isset($argv[0]) || empty($argv[0])) { - $version = $this->ask('Enter new version of your plugin:'); - } elseif ($this->isHelp()) { - $this->line("\nUsage:"); - $this->info(" version [plugin version]\n"); - $this->line('Arguments:'); - $this->info( - " [plugin version]\t\tThe version of plugin. Examples: '2.0', 'v1.2', '1.2.0-rc.40', 'v1-beta.4'" - ); - $this->info(" [--major]\t\t\tIncrement the .y.z of plugin."); - $this->info(" [--minor]\t\t\tIncrement the x..z of plugin."); - $this->info(" [--patch]\t\t\tIncrement the x.y. of plugin."); - $this->info( - " [--pre-patch] \tIncrement the x.y.-. of plugin." - ); - $this->info( - " [--pre-minor] \tIncrement the x..z-. of plugin." - ); - $this->info( - " [--pre-major] \tIncrement the .y.z-. of plugin.\n" - ); - exit(0); - } elseif (isset($argv[0]) && '--patch' === $argv[0]) { - $version = semver($version_number_from_index_php)->incrementPatch(); - } elseif (isset($argv[0]) && '--minor' === $argv[0]) { - $version = semver($version_number_from_index_php)->incrementMinor(); - } elseif (isset($argv[0]) && '--major' === $argv[0]) { - $version = semver($version_number_from_index_php)->incrementMajor(); - } elseif ( - isset($argv[0]) && - in_array($argv[0], ['--pre-patch', '--pre-major', '--pre-minor']) - ) { - $prefix = $argv[1] ?? 'rc'; - - $methods = [ - '--pre-patch' => 'incrementPatch', - '--pre-major' => 'incrementMajor', - '--pre-minor' => 'incrementMinor', - ]; - // if $version_number_from_index_php is not a pre-release version - if (strpos($version_number_from_index_php, $prefix) === false) { - $prerelease = semver($version_number_from_index_php)->{$methods[$argv[0]]}(); - $version = semver($prerelease) - ->setPreRelease($prefix) - ->incrementPreRelease(); - } else { - $version = semver( - $version_number_from_index_php - )->incrementPreRelease(); - } - } else { - $version = trim($argv[0]); - } - - if ($version === '') { - $version = semver($version_number_from_index_php)->incrementPatch(); - } - - try { - $version = Version::parse($version); - } catch (\Bones\SemVer\Exceptions\InvalidVersionException $e) { - $this->error("\nERROR:\n\nThe version is not valid.\n"); - exit(1); - } - - $yesno = $this->ask( - "The new version of your plugin will be {$version}, is it ok? (y/n)", - 'n' - ); - - if (strtolower($yesno) != 'y') { - return; - } - - if ( - $version != $version_number_from_index_php || - $version != $version_number_from_readme_txt - ) { - // We're going to change the "Stable tag: x.y.z" with "Stable tag: $version" - $new_stable_tag_version_for_readme_txt = str_replace( - $version_number_from_readme_txt, - $version, - $stable_tag_version_from_readme_txt - ); - - // We're going to change the whole "readme.txt" file - $new_readme_txt_content = str_replace( - $stable_tag_version_from_readme_txt, - $new_stable_tag_version_for_readme_txt, - $readme_txt_content - ); - - file_put_contents('readme.txt', $new_readme_txt_content); - - // We're going to change the "* Version: x.y.z" with "* Version: $version" - $new_version_string_for_index_php = str_replace( - $version_number_from_index_php, - $version, - $version_string_from_index_php - ); - - // We're going to change the whole "index.php" file - $new_index_php_content = str_replace( - $version_string_from_index_php, - $new_version_string_for_index_php, - $index_php_content - ); - - file_put_contents('index.php', $new_index_php_content); - - $this->line("\nVersion updated to {$version}"); - - return; - } - - $this->line("\nVersion is already {$version}"); - } + try { + $version = Version::parse($version); + } catch (InvalidVersionException $e) { + $this->error("\nERROR:\n\nThe version is not valid.\n"); + exit(1); + } - /** - * Commodity to display an error message in the console. - * - * @param string $str The message to display. - */ - protected function error($str) - { - echo "\033[41m\n"; - echo "\033[41;255m" . $str . "\n"; - echo "\033[0m\n"; - } + $yesno = $this->ask( + "The new version of your plugin will be {$version}, is it ok? (y/n)", + 'n' + ); - /** - * Create a migrate file - * - * @param string $tablename - */ - protected function createMigrate($tablename) - { - if ($this->isHelp($tablename)) { - $this->info('Use php bones migrate:make '); + if (strtolower($yesno) != 'y') { + return; + } - return; - } + if ( + $version != $version_number_from_index_php || + $version != $version_number_from_readme_txt + ) { + // We're going to change the "Stable tag: x.y.z" with "Stable tag: $version" + $new_stable_tag_version_for_readme_txt = str_replace( + $version_number_from_readme_txt, + $version, + $stable_tag_version_from_readme_txt + ); + + // We're going to change the whole "readme.txt" file + $new_readme_txt_content = str_replace( + $stable_tag_version_from_readme_txt, + $new_stable_tag_version_for_readme_txt, + $readme_txt_content + ); + + file_put_contents('readme.txt', $new_readme_txt_content); + + // We're going to change the "* Version: x.y.z" with "* Version: $version" + $new_version_string_for_index_php = str_replace( + $version_number_from_index_php, + $version, + $version_string_from_index_php + ); + + // We're going to change the whole main plugin file + $new_index_php_content = str_replace( + $version_string_from_index_php, + $new_version_string_for_index_php, + $index_php_content + ); + + file_put_contents($mainPluginFilename, $new_index_php_content); + + $this->line("\nVersion updated to {$version}"); + + return; + } - $filename = sprintf( - '%s_create_%s_table.php', - date('Y_m_d_His'), - strtolower($tablename) - ); + $this->line("\nVersion is already {$version}"); + } - // current plugin name and namespace - $namespace = $this->getNamespace(); + /** + * Create a migrate file + * + * @param string $tablename + */ + protected function createMigrate($tablename) + { + if ($this->isHelp($tablename)) { + $this->info('Use php bones migrate:make '); - // stubbing - $content = $this->prepareStub('migrate', [ - '{Namespace}' => $namespace, - '{Tablename}' => $tablename, - ]); + return; + } - file_put_contents("database/migrations/{$filename}", $content); + $filename = sprintf( + '%s_create_%s_table.php', + date('Y_m_d_His'), + strtolower($tablename) + ); - $this->line(" Created database/migrations/{$filename}"); - } + // current plugin name and namespace + $namespace = $this->getNamespace(); - /** - * Return the content of a stub file with all replacements. - * - * @param string $filename The stub file name without extension - * @param array $replacements - * @return string - */ - public function prepareStub($filename, $replacements = []): string - { - $stub = $this->getStubContent($filename); + // stubbing + $content = $this->prepareStub('migrate', [ + '{Namespace}' => $namespace, + '{Tablename}' => $tablename, + ]); - return str_replace( - array_keys($replacements), - array_values($replacements), - $stub - ); - } + file_put_contents("database/migrations/{$filename}", $content); - /** - * Return the content of a stub file. - * - * @param $filename - * @return string - */ - public function getStubContent($filename): string - { - return file_get_contents( - "vendor/wpbones/wpbones/src/Console/stubs/{$filename}.stub" - ); - } + $this->line(" Created database/migrations/{$filename}"); + } - /** - * Create a controller - * - * @param string $className The class name - */ - protected function createController($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:controller '); - $this->line('Or'); - $this->info('Use php bones make:controller /'); + /** + * Return the content of a stub file with all replacements. + * + * @param string $filename The stub file name without extension + * @param array $replacements + * @return string + */ + public function prepareStub($filename, $replacements = []): string + { + $stub = $this->getStubContent($filename); + + return str_replace( + array_keys($replacements), + array_values($replacements), + $stub + ); + } - return; - } + /** + * Return the content of a stub file. + * + * @param $filename + * @return string + */ + public function getStubContent($filename): string + { + return file_get_contents( + "vendor/wpbones/wpbones/src/Console/stubs/{$filename}.stub" + ); + } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + /** + * Create a controller + * + * @param string $className The class name + */ + protected function createController($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:controller '); + $this->line('Or'); + $this->info('Use php bones make:controller /'); + + return; + } - // current plugin name and namespace - $namespace = $this->getNamespace(); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - // get additional path - $path = $namespacePath = ''; - if (false !== strpos($className, '/')) { - $parts = explode('/', $className); - $className = array_pop($parts); - $path = implode('/', $parts) . '/'; - $namespacePath = '\\' . implode('\\', $parts); - } + // current plugin name and namespace + $namespace = $this->getNamespace(); - // stubbing - $content = $this->prepareStub('controller', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // get additional path + $path = $namespacePath = ''; + if (false !== strpos($className, '/')) { + $parts = explode('/', $className); + $className = array_pop($parts); + $path = implode('/', $parts) . '/'; + $namespacePath = '\\' . implode('\\', $parts); + } - if (!empty($path)) { - $content = str_replace('{Path}', $namespacePath, $content); - mkdir("plugin/Http/Controllers/{$path}", 0777, true); - } else { - $content = str_replace('{Path}', '', $content); - } + // stubbing + $content = $this->prepareStub('controller', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - $filename = sprintf('%s.php', $className); + if (!empty($path)) { + $content = str_replace('{Path}', $namespacePath, $content); + mkdir("plugin/Http/Controllers/{$path}", 0777, true); + } else { + $content = str_replace('{Path}', '', $content); + } - file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); + $filename = sprintf('%s.php', $className); - $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); + file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); - $this->optimize(); - } + $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); - /** - * Commodity function to check if ClassName has been requested. - * - * @param string $className Optional. Command to check. - * - * @return string - */ - protected function askClassNameIfEmpty($className = ''): string - { - if (empty($className)) { - $className = $this->ask('ClassName:'); - if (empty($className)) { - $this->error('ClassName is required'); - exit(0); + $this->optimize(); } - } - - return $className; - } - - /** - * Create a Command controller - * - * @param string $className The class name - */ - protected function createCommand($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:console '); - - return; - } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + /** + * Commodity function to check if ClassName has been requested. + * + * @param string $className Optional. Command to check. + * + * @return string + */ + protected function askClassNameIfEmpty($className = ''): string + { + if (empty($className)) { + $className = $this->ask('ClassName:'); + if (empty($className)) { + $this->error('ClassName is required'); + exit(0); + } + } - $filename = sprintf('%s.php', $className); + return $className; + } - // current plugin name and namespace - [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); + /** + * Create a Command controller + * + * @param string $className The class name + */ + protected function createCommand($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:console '); - $signature = str_replace('-', '', $this->sanitize($pluginName)); - $command = str_replace('-', '', $this->sanitize($className)); + return; + } - $signature = $this->ask('Enter a signature:', $signature); - $command = $this->ask('Enter the command:', $command); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - // stubbing - $content = $this->prepareStub('command', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - '{Signature}' => $signature, - '{CommandName}' => $command, - ]); + $filename = sprintf('%s.php', $className); - if (!is_dir('plugin/Console/Commands')) { - mkdir('plugin/Console/Commands', 0777, true); - } + // current plugin name and namespace + [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); - file_put_contents("plugin/Console/Commands/{$filename}", $content); + $signature = str_replace('-', '', $this->sanitize($pluginName)); + $command = str_replace('-', '', $this->sanitize($className)); - $this->line(" Created plugin/Console/Commands/{$filename}"); + $signature = $this->ask('Enter a signature:', $signature); + $command = $this->ask('Enter the command:', $command); - // check if plugin/Console/Kernel.php already exists - if (file_exists('plugin/Console/Kernel.php')) { - $this->info( - "Remember to add {$className} in the plugin/Console/Commands/Kernel.php property array \$commands" - ); - } else { - // stubbing - $content = $this->prepareStub('kernel', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // stubbing + $content = $this->prepareStub('command', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + '{Signature}' => $signature, + '{CommandName}' => $command, + ]); - file_put_contents('plugin/Console/Kernel.php', $content); + if (!is_dir('plugin/Console/Commands')) { + mkdir('plugin/Console/Commands', 0777, true); + } - $this->line(' Created plugin/Console/Kernel.php'); - } - } + file_put_contents("plugin/Console/Commands/{$filename}", $content); - /** - * Create a Custom Post Type controller - * - * @param string $className The class name - */ - protected function createCustomPostType($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:cpt '); + $this->line(" Created plugin/Console/Commands/{$filename}"); - return; - } + // check if plugin/Console/Kernel.php already exists + if (file_exists('plugin/Console/Kernel.php')) { + $this->info( + "Remember to add {$className} in the plugin/Console/Commands/Kernel.php property array \$commands" + ); + } else { + // stubbing + $content = $this->prepareStub('kernel', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + file_put_contents('plugin/Console/Kernel.php', $content); - $filename = sprintf('%s.php', $className); + $this->line(' Created plugin/Console/Kernel.php'); + } + } - // current plugin name and namespace - [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); + /** + * Create a Custom Post Type controller + * + * @param string $className The class name + */ + protected function createCustomPostType($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:cpt '); - $slug = str_replace('-', '_', $this->sanitize($pluginName)); + return; + } - $id = $this->ask('Enter a ID:', $slug); - $name = $this->ask('Enter the name:'); - $plural = $this->ask('Enter the plural name:'); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - if (empty($id)) { - $id = $slug; - } + $filename = sprintf('%s.php', $className); - // stubbing - $content = $this->prepareStub('cpt', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - '{ID}' => $id, - '{Name}' => $name, - '{Plural}' => $plural, - ]); + // current plugin name and namespace + [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); - if (!is_dir('plugin/CustomPostTypes')) { - mkdir('plugin/CustomPostTypes', 0777, true); - } + $slug = str_replace('-', '_', $this->sanitize($pluginName)); - file_put_contents("plugin/CustomPostTypes/{$filename}", $content); + $id = $this->ask('Enter a ID:', $slug); + $name = $this->ask('Enter the name:'); + $plural = $this->ask('Enter the plural name:'); - $this->line(" Created plugin/CustomPostTypes/{$filename}"); + if (empty($id)) { + $id = $slug; + } - $this->info( - "Remember to add {$className} in the config/plugin.php array in the 'custom_post_types' key." - ); - } + // stubbing + $content = $this->prepareStub('cpt', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + '{ID}' => $id, + '{Name}' => $name, + '{Plural}' => $plural, + ]); + + if (!is_dir('plugin/CustomPostTypes')) { + mkdir('plugin/CustomPostTypes', 0777, true); + } - /** - * Create a Shortcode controller - * - * @param string $className The class name - */ - protected function createShortcode($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:shortcode '); + file_put_contents("plugin/CustomPostTypes/{$filename}", $content); - return; - } + $this->line(" Created plugin/CustomPostTypes/{$filename}"); - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + $this->info( + "Remember to add {$className} in the config/plugin.php array in the 'custom_post_types' key." + ); + } - $filename = sprintf('%s.php', $className); + /** + * Create a Shortcode controller + * + * @param string $className The class name + */ + protected function createShortcode($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:shortcode '); - // current plugin name and namespace - $namespace = $this->getNamespace(); + return; + } - // stubbing - $content = $this->prepareStub('shortcode', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - if (!is_dir('plugin/Shortcodes')) { - mkdir('plugin/Shortcodes', 0777, true); - } + $filename = sprintf('%s.php', $className); - file_put_contents("plugin/Shortcodes/{$filename}", $content); + // current plugin name and namespace + $namespace = $this->getNamespace(); - $this->line(" Created plugin/Shortcodes/{$filename}"); + // stubbing + $content = $this->prepareStub('shortcode', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - $this->info( - "Remember to add {$className} in the config/plugin.php array in the 'shortcodes' key." - ); - } + if (!is_dir('plugin/Shortcodes')) { + mkdir('plugin/Shortcodes', 0777, true); + } - /** - * Create a Service Provider - * - * @param string $className The class name - */ - protected function createProvider($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:provider '); + file_put_contents("plugin/Shortcodes/{$filename}", $content); - return; - } + $this->line(" Created plugin/Shortcodes/{$filename}"); - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + $this->info( + "Remember to add {$className} in the config/plugin.php array in the 'shortcodes' key." + ); + } - $filename = sprintf('%s.php', $className); + /** + * Create a Service Provider + * + * @param string $className The class name + */ + protected function createProvider($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:provider '); - // current plugin name and namespace - $namespace = $this->getNamespace(); + return; + } - // stubbing - $content = $this->prepareStub('provider', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - if (!is_dir('plugin/Providers')) { - mkdir('plugin/Providers', 0777, true); - } + $filename = sprintf('%s.php', $className); - file_put_contents("plugin/Providers/{$filename}", $content); + // current plugin name and namespace + $namespace = $this->getNamespace(); - $this->line(" Created plugin/Providers/{$filename}"); - } + // stubbing + $content = $this->prepareStub('provider', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - /** - * Create a Ajax controller - * - * @param string $className The class name - */ - protected function createAjax($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:ajax '); + if (!is_dir('plugin/Providers')) { + mkdir('plugin/Providers', 0777, true); + } - return; - } + file_put_contents("plugin/Providers/{$filename}", $content); - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + $this->line(" Created plugin/Providers/{$filename}"); + } - // current plugin name and namespace - $namespace = $this->getNamespace(); + /** + * Create a Ajax controller + * + * @param string $className The class name + */ + protected function createAjax($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:ajax '); - // stubbing - $content = $this->prepareStub('ajax', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + return; + } - if (!is_dir('plugin/Ajax')) { - mkdir('plugin/Ajax', 0777, true); - } + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - $filename = sprintf('%s.php', $className); + // current plugin name and namespace + $namespace = $this->getNamespace(); - file_put_contents("plugin/Ajax/{$filename}", $content); + // stubbing + $content = $this->prepareStub('ajax', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - $this->line(" Created plugin/Ajax/{$filename}"); + if (!is_dir('plugin/Ajax')) { + mkdir('plugin/Ajax', 0777, true); + } - $this->info( - "Remember to add {$className} in the config/plugin.php array in the 'ajax' key." - ); - } + $filename = sprintf('%s.php', $className); - /** - * Create a Custom Taxonomy controller - * - * @param string $className The class name - */ - protected function createCustomTaxonomyType($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:ctt '); + file_put_contents("plugin/Ajax/{$filename}", $content); - return; - } + $this->line(" Created plugin/Ajax/{$filename}"); - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + $this->info( + "Remember to add {$className} in the config/plugin.php array in the 'ajax' key." + ); + } - $filename = sprintf('%s.php', $className); + /** + * Create a Custom Taxonomy controller + * + * @param string $className The class name + */ + protected function createCustomTaxonomyType($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:ctt '); - // current plugin name and namespace - $namespace = $this->getNamespace(); + return; + } - $slug = $this->getPluginId(); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - $id = $this->ask('Enter a ID:', $slug); - $name = $this->ask('Enter the name:'); - $plural = $this->ask('Enter the plural name:'); + $filename = sprintf('%s.php', $className); - $this->line( - 'The object type below refers to the id of your previous Custom Post Type' - ); + // current plugin name and namespace + $namespace = $this->getNamespace(); - $objectType = $this->ask('Enter the object type to bound:'); + $slug = $this->getPluginId(); - if (empty($id)) { - $id = $slug; - } + $id = $this->ask('Enter a ID:', $slug); + $name = $this->ask('Enter the name:'); + $plural = $this->ask('Enter the plural name:'); - // stubbing - $content = $this->prepareStub('ctt', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - '{ID}' => $id, - '{Name}' => $name, - '{Plural}' => $plural, - '{ObjectType}' => $objectType, - ]); + $this->line( + 'The object type below refers to the id of your previous Custom Post Type' + ); - if (!is_dir('plugin/CustomTaxonomyTypes')) { - mkdir('plugin/CustomTaxonomyTypes', 0777, true); - } + $objectType = $this->ask('Enter the object type to bound:'); - file_put_contents("plugin/CustomTaxonomyTypes/{$filename}", $content); + if (empty($id)) { + $id = $slug; + } - $this->line(" Created plugin/CustomTaxonomyTypes/{$filename}"); + // stubbing + $content = $this->prepareStub('ctt', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + '{ID}' => $id, + '{Name}' => $name, + '{Plural}' => $plural, + '{ObjectType}' => $objectType, + ]); + + if (!is_dir('plugin/CustomTaxonomyTypes')) { + mkdir('plugin/CustomTaxonomyTypes', 0777, true); + } - $this->info( - "Remember to add {$className} in the config/plugin.php array in the 'custom_taxonomy_types' key." - ); - } + file_put_contents("plugin/CustomTaxonomyTypes/{$filename}", $content); - /** - * Create a Widget controller - * - * @param string $className The class name - */ - protected function createWidget($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:widget '); + $this->line(" Created plugin/CustomTaxonomyTypes/{$filename}"); - return; - } + $this->info( + "Remember to add {$className} in the config/plugin.php array in the 'custom_taxonomy_types' key." + ); + } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + /** + * Create a Widget controller + * + * @param string $className The class name + */ + protected function createWidget($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:widget '); - $filename = sprintf('%s.php', $className); + return; + } - // current plugin name and namespace - [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - $slug = $this->getPluginId(); + $filename = sprintf('%s.php', $className); - // stubbing - $content = $this->prepareStub('widget', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - '{PluginName}' => $pluginName, - '{Slug}' => $slug, - ]); + // current plugin name and namespace + [$pluginName, $namespace] = $this->getPluginNameAndNamespace(); - if (!is_dir('plugin/Widgets')) { - mkdir('plugin/Widgets', 0777, true); - } + $slug = $this->getPluginId(); - file_put_contents("plugin/Widgets/{$filename}", $content); + // stubbing + $content = $this->prepareStub('widget', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + '{PluginName}' => $pluginName, + '{Slug}' => $slug, + ]); - $this->line(" Created plugin/Widgets/{$filename}"); + if (!is_dir('plugin/Widgets')) { + mkdir('plugin/Widgets', 0777, true); + } - if (!is_dir('resources/views/widgets')) { - mkdir('resources/views/widgets', 0777, true); - } + file_put_contents("plugin/Widgets/{$filename}", $content); - file_put_contents( - "resources/views/widgets/{$slug}-form.php", - '

Backend form

' - ); - file_put_contents( - "resources/views/widgets/{$slug}-index.php", - '

Frontend Widget output

' - ); + $this->line(" Created plugin/Widgets/{$filename}"); - $this->line(" Created resources/views/widgets/{$slug}-form.php"); - $this->line(" Created resources/views/widgets/{$slug}-index.php"); + if (!is_dir('resources/views/widgets')) { + mkdir('resources/views/widgets', 0777, true); + } - $this->info( - "Remember to add {$className} in the config/plugin.php array in the 'widgets' key." - ); - } + file_put_contents( + "resources/views/widgets/{$slug}-form.php", + '

Backend form

' + ); + file_put_contents( + "resources/views/widgets/{$slug}-index.php", + '

Frontend Widget output

' + ); + + $this->line(" Created resources/views/widgets/{$slug}-form.php"); + $this->line(" Created resources/views/widgets/{$slug}-index.php"); + + $this->info( + "Remember to add {$className} in the config/plugin.php array in the 'widgets' key." + ); + } - /** - * Create a database Model - * - * @param string $className The class name - */ - protected function createModel($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:model '); + /** + * Create a database Model + * + * @param string $className The class name + */ + protected function createModel($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:model '); - return; - } + return; + } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - // current plugin name and namespace - $namespace = $this->getNamespace(); + // current plugin name and namespace + $namespace = $this->getNamespace(); - // get additional path - $path = $namespacePath = ''; - if (false !== strpos($className, '/')) { - $parts = explode('/', $className); - $className = array_pop($parts); - $path = implode('/', $parts) . '/'; - $namespacePath = '\\' . implode('\\', $parts); - } + // get additional path + $path = $namespacePath = ''; + if (false !== strpos($className, '/')) { + $parts = explode('/', $className); + $className = array_pop($parts); + $path = implode('/', $parts) . '/'; + $namespacePath = '\\' . implode('\\', $parts); + } - // stubbing - $content = $this->prepareStub('model', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // stubbing + $content = $this->prepareStub('model', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - if (!empty($path)) { - $content = str_replace('{Path}', $namespacePath, $content); - mkdir("plugin/Http/Controllers/{$path}", 0777, true); - } else { - $content = str_replace('{Path}', '', $content); - } + if (!empty($path)) { + $content = str_replace('{Path}', $namespacePath, $content); + mkdir("plugin/Http/Controllers/{$path}", 0777, true); + } else { + $content = str_replace('{Path}', '', $content); + } - $filename = sprintf('%s.php', $className); + $filename = sprintf('%s.php', $className); - file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); + file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); - $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); + $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); - $this->optimize(); - } + $this->optimize(); + } - /** - * Create a Eloquent database Model - * - * @param string $className The class name - */ - protected function createEloquentModel($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:eloquent-model '); + /** + * Create a Eloquent database Model + * + * @param string $className The class name + */ + protected function createEloquentModel($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:eloquent-model '); - return; - } + return; + } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - // current plugin name and namespace - $namespace = $this->getNamespace(); + // current plugin name and namespace + $namespace = $this->getNamespace(); - // get additional path - $path = $namespacePath = ''; - if (false !== strpos($className, '/')) { - $parts = explode('/', $className); - $className = array_pop($parts); - $path = implode('/', $parts) . '/'; - $namespacePath = '\\' . implode('\\', $parts); - } + // get additional path + $path = $namespacePath = ''; + if (false !== strpos($className, '/')) { + $parts = explode('/', $className); + $className = array_pop($parts); + $path = implode('/', $parts) . '/'; + $namespacePath = '\\' . implode('\\', $parts); + } - // create the table - $table = strtolower($className); + // create the table + $table = strtolower($className); - // stubbing - $content = $this->prepareStub('eloquent-model', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - '{Table}' => $table, - ]); + // stubbing + $content = $this->prepareStub('eloquent-model', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + '{Table}' => $table, + ]); - if (!empty($path)) { - $content = str_replace('{Path}', $namespacePath, $content); - mkdir("plugin/Http/Controllers/{$path}", 0777, true); - } else { - $content = str_replace('{Path}', '', $content); - } + if (!empty($path)) { + $content = str_replace('{Path}', $namespacePath, $content); + mkdir("plugin/Http/Controllers/{$path}", 0777, true); + } else { + $content = str_replace('{Path}', '', $content); + } - $filename = sprintf('%s.php', $className); + $filename = sprintf('%s.php', $className); - file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); + file_put_contents("plugin/Http/Controllers/{$path}{$filename}", $content); - $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); + $this->line(" Created plugin/Http/Controllers/{$path}{$filename}"); - $this->optimize(); - } + $this->optimize(); + } - /** - * Create an API Controller - * - * @param string $className The class name - */ - protected function createAPIController($className) - { - if ($this->isHelp($className)) { - $this->info('Use php bones make:api '); + /** + * Create an API Controller + * + * @param string $className The class name + */ + protected function createAPIController($className) + { + if ($this->isHelp($className)) { + $this->info('Use php bones make:api '); - return; - } + return; + } - // ask className if empty - $className = $this->askClassNameIfEmpty($className); + // ask className if empty + $className = $this->askClassNameIfEmpty($className); - // current plugin name and namespace - $namespace = $this->getNamespace(); + // current plugin name and namespace + $namespace = $this->getNamespace(); - // get additional path - $path = $namespacePath = ''; - if (false !== strpos($className, '/')) { - $parts = explode('/', $className); - $className = array_pop($parts); - $path = implode('/', $parts) . '/'; - $namespacePath = '\\' . implode('\\', $parts); - } + // get additional path + $path = $namespacePath = ''; + if (false !== strpos($className, '/')) { + $parts = explode('/', $className); + $className = array_pop($parts); + $path = implode('/', $parts) . '/'; + $namespacePath = '\\' . implode('\\', $parts); + } - // stubbing - $content = $this->prepareStub('api', [ - '{Namespace}' => $namespace, - '{ClassName}' => $className, - ]); + // stubbing + $content = $this->prepareStub('api', [ + '{Namespace}' => $namespace, + '{ClassName}' => $className, + ]); - if (!empty($path)) { - $content = str_replace('{Path}', $namespacePath, $content); - mkdir("plugin/API/{$path}", 0777, true); - } else { - $content = str_replace('{Path}', '', $content); - } + if (!empty($path)) { + $content = str_replace('{Path}', $namespacePath, $content); + mkdir("plugin/API/{$path}", 0777, true); + } else { + $content = str_replace('{Path}', '', $content); + } - $filename = sprintf('%s.php', $className); + $filename = sprintf('%s.php', $className); - file_put_contents("plugin/API/{$path}{$filename}", $content); + file_put_contents("plugin/API/{$path}{$filename}", $content); - $this->line(" Created plugin/API/{$path}{$filename}"); + $this->line(" Created plugin/API/{$path}{$filename}"); - $this->optimize(); - } + $this->optimize(); + } - /** - * Let's roll - * - * @return \Bones\BonesCommandLine - */ - public static function run(): BonesCommandLine - { - return new self(); + /** + * Let's roll + * + * @return BonesCommandLine + */ + public static function run(): BonesCommandLine + { + return new self(); + } } - } - BonesCommandLine::run(); + BonesCommandLine::run(); } diff --git a/src/Foundation/Plugin.php b/src/Foundation/Plugin.php index 1633f88..5bec1bf 100644 --- a/src/Foundation/Plugin.php +++ b/src/Foundation/Plugin.php @@ -17,7 +17,7 @@ use WPKirk\WPBones\View\View; if (!defined('ABSPATH')) { - exit(); + exit(); } /** @@ -25,673 +25,670 @@ * @package WPKirk\WPBones\Foundation * * @property WordPressOption $options - * @property Request $request - * @property string $Version + * @property Request $request + * @property string $Version */ class Plugin extends Container implements PluginContract { - use HasAttributes; - - /** - * The current globally available container (if any). - * - * @var Plugin - */ - protected static $instance; - - /** - * The slug of this plugin. - * - * @var string - */ - public $slug = ''; - - /** - * Build in __FILE__ relative plugin. - * - * @var string - */ - protected $file; - - /** - * The base path for the plugin installation. - * - * @var string - */ - protected $basePath; - - /** - * The base uri for the plugin installation. - * - * @var string - */ - protected $baseUri; - - /** - * Internal use where store the plugin data. - * - * @var array - */ - protected $pluginData = []; - - /** - * A key value pairs array with the list of providers. - * - * @var array - */ - protected $provides = []; - private $_options = null; - private $_request = null; - - public function __construct($basePath) - { - $this->basePath = rtrim($basePath, '\/'); - - $this->boot(); - } - - public function boot(): Plugin - { - // simulate __FILE__ - $this->file = $this->basePath . '/index.php'; - - $this->baseUri = rtrim(plugin_dir_url($this->file), '\/'); - - // Use WordPress get_plugin_data() function for auto retrieve plugin information. - if (!function_exists('get_plugin_data')) { - require_once ABSPATH . 'wp-admin/includes/plugin.php'; - } - $this->pluginData = get_plugin_data($this->file, false); + use HasAttributes; - /* - * In $this->pluginData you'll find all WordPress - * - * Author = "Giovambattista Fazioli" - * AuthorName = "Giovambattista Fazioli" - * AuthorURI = "http://undolog.com" - * Description = "WPKirk is a WP Bones boilperate plugin" - * DomainPath = "localization" - * Name = "WPKirk" - * Network = false - * PluginURI = "http://undolog.com" - * TextDomain = "wp-kirk" - * Title = "WPKirk" - * Version = "1.0.0" + /** + * The current globally available container (if any). + * + * @var Plugin */ + protected static $instance; - // plugin slug - $this->slug = str_replace('-', '_', sanitize_title($this->pluginData['Name'])) . '_slug'; + /** + * The slug of this plugin. + * + * @var string + */ + public $slug = ''; - // Load text domain - load_plugin_textdomain( - 'wp-kirk', - false, - trailingslashit(basename($this->basePath)) . $this->pluginData['DomainPath'] - ); + /** + * Build in __FILE__ relative plugin. + * + * @var string + */ + protected $file; - // Activation & Deactivation Hook - register_activation_hook($this->file, [$this, 'activation']); - register_deactivation_hook($this->file, [$this, 'deactivation']); + /** + * The base path for the plugin installation. + * + * @var string + */ + protected $basePath; - // handle plugin update - add_filter('upgrader_post_install', [$this, 'upgrader_post_install'], 10, 3); + /** + * The base uri for the plugin installation. + * + * @var string + */ + protected $baseUri; - /* - * There are many pitfalls to using the uninstall hook. It ’ s a much cleaner, and easier, process to use the - * uninstall.php method for removing plugin settings and options when a plugin is deleted in WordPress. + /** + * Internal use where store the plugin data. * - * Using uninstall.php file. This is typically the preferred method because it keeps all your uninstall code in a - * separate file. To use this method, create an uninstall.php file and place it in the root directory of your - * plugin. If this file exists WordPress executes its contents when the plugin is deleted from the WordPress - * Plugins screen page. + * @var array + */ + protected $pluginData = []; + + /** + * A key value pairs array with the list of providers. * + * @var array */ + protected $provides = []; + private $_options = null; + private $_request = null; - // register_uninstall_hook( $file, array( $this, 'uninstall' ) ); + public function __construct($basePath) + { + $this->basePath = rtrim($basePath, '\/'); - // Log - $this->provides['Log'] = (new LogServiceProvider($this))->register(); + $this->boot(); + } - // init Eloquent out of box - $this->initEloquent(); + public function boot(): Plugin + { + // simulate __FILE__ + $this->file = $this->basePath . '/wp-kirk.php'; - // init api - $this->initApi(); + $this->baseUri = rtrim(plugin_dir_url($this->file), '\/'); - // Fires after WordPress has finished loading but before any headers are sent. - add_action('init', [$this, 'init']); + // Use WordPress get_plugin_data() function for auto retrieve plugin information. + if (!function_exists('get_plugin_data')) { + require_once ABSPATH . 'wp-admin/includes/plugin.php'; + } + $this->pluginData = get_plugin_data($this->file, false); + + /* + * In $this->pluginData you'll find all WordPress + * + * Author = "Giovambattista Fazioli" + * AuthorName = "Giovambattista Fazioli" + * AuthorURI = "http://undolog.com" + * Description = "WPKirk is a WP Bones boilerplate plugin" + * DomainPath = "localization" + * Name = "WPKirk" + * Network = false + * PluginURI = "http://undolog.com" + * TextDomain = "wp-kirk" + * Title = "WPKirk" + * Version = "1.0.0" + */ + + // plugin slug + $this->slug = str_replace('-', '_', sanitize_title($this->pluginData['Name'])) . '_slug'; + + // Load text domain + load_plugin_textdomain( + 'wp-kirk', + false, + trailingslashit(basename($this->basePath)) . $this->pluginData['DomainPath'] + ); + + // Activation & Deactivation Hook + register_activation_hook($this->file, [$this, 'activation']); + register_deactivation_hook($this->file, [$this, 'deactivation']); + + // handle plugin update + add_filter('upgrader_post_install', [$this, 'upgrader_post_install'], 10, 3); + + /* + * There are many pitfalls to using the uninstall hook. It ’ s a much cleaner, and easier, process to use the + * uninstall.php method for removing plugin settings and options when a plugin is deleted in WordPress. + * + * Using uninstall.php file. This is typically the preferred method because it keeps all your uninstall code in a + * separate file. To use this method, create an uninstall.php file and place it in the root directory of your + * plugin. If this file exists WordPress executes its contents when the plugin is deleted from the WordPress + * Plugins screen page. + * + */ + + // register_uninstall_hook( $file, array( $this, 'uninstall' ) ); + + // Log + $this->provides['Log'] = (new LogServiceProvider($this))->register(); + + // init Eloquent out of box + $this->initEloquent(); + + // init api + $this->initApi(); + + // Fires after WordPress has finished loading but before any headers are sent. + add_action('init', [$this, 'init']); + + // Fires before the administration menu loads in the admin. + add_action('admin_menu', [$this, 'admin_menu']); + + // Fires after all default WordPress widgets have been registered. + add_action('widgets_init', [$this, 'widgets_init']); + + // Filter a screen option value before it is set. + add_filter('set-screen-option', [$this, 'set_screen_option'], 10, 3); + + static::$instance = $this; + + return $this; + } - // Fires before the administration menu loads in the admin. - add_action('admin_menu', [$this, 'admin_menu']); + private function initEloquent() + { + $eloquent = '\Illuminate\Database\Capsule\Manager'; + if (class_exists($eloquent)) { + $capsule = new $eloquent(); + + $capsule->addConnection([ + 'driver' => 'mysql', + 'host' => DB_HOST, + 'database' => DB_NAME, + 'username' => DB_USER, + 'password' => DB_PASSWORD, + 'charset' => 'utf8', + 'collation' => 'utf8_unicode_ci', + 'prefix' => '', + ]); + + // Set the event dispatcher used by Eloquent models... (optional) + // use Illuminate\Events\Dispatcher; + // use Illuminate\Container\Container; + // $capsule->setEventDispatcher(new Dispatcher(new Container)); + + // Make this Capsule instance available globally via static methods... (optional) + $capsule->setAsGlobal(); + + // Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher()) + $capsule->bootEloquent(); + } + } - // Fires after all default WordPress widgets have been registered. - add_action('widgets_init', [$this, 'widgets_init']); + private function initApi() + { + (new RestProvider($this))->register(); + } - // Filter a screen option value before it is set. - add_filter('set-screen-option', [$this, 'set_screen_option'], 10, 3); + public function __get($name) + { + if ($this->hasGetMutator($name)) { + return $this->mutateAttribute($name); + } + + if (in_array($name, array_keys($this->pluginData))) { + return $this->pluginData[$name]; + } + } + + public function set_screen_option($status, $option, $value) + { + if (in_array($option, array_values($this->config('plugin.screen_options', [])))) { + return $value; + } + + return $status; + } + + /** + * Get / set the specified configuration value. + * + * If an array is passed as the key, we will assume you want to set an array of values. + * + * @param array|string $key + * @param mixed $default + * + * @return mixed + */ + public function config($key = null, $default = null) + { + if (is_null($key)) { + return []; + } - static::$instance = $this; + $parts = explode('.', $key); + + $filename = "{$parts[0]}.php"; + $key = $parts[1] ?? null; + + $array = include "{$this->basePath}/config/{$filename}"; + + if (is_null($key)) { + return $array; + } - return $this; - } + unset($parts[0]); - private function initEloquent() - { - $eloquent = '\Illuminate\Database\Capsule\Manager'; - if (class_exists($eloquent)) { - $capsule = new $eloquent(); + foreach ($parts as $segment) { + if (!is_array($array) || !array_key_exists($segment, $array)) { + return wpbones_value($default); + } - $capsule->addConnection([ - 'driver' => 'mysql', - 'host' => DB_HOST, - 'database' => DB_NAME, - 'username' => DB_USER, - 'password' => DB_PASSWORD, - 'charset' => 'utf8', - 'collation' => 'utf8_unicode_ci', - 'prefix' => '', - ]); + $array = $array[$segment]; + } - // Set the event dispatcher used by Eloquent models... (optional) - // use Illuminate\Events\Dispatcher; - // use Illuminate\Container\Container; - // $capsule->setEventDispatcher(new Dispatcher(new Container)); + return $array; + } - // Make this Capsule instance available globally via static methods... (optional) - $capsule->setAsGlobal(); + /** + * Get the base path of the plugin installation. + * + * @return string + */ + public function getBasePath(): string + { + return $this->basePath; + } - // Setup the Eloquent ORM... (optional; unless you've used setEventDispatcher()) - $capsule->bootEloquent(); + /** + * Return the absolute URL for the installation plugin. + * + * @return string + */ + public function getBaseUri(): string + { + return $this->baseUri; } - } - private function initApi() - { - (new RestProvider($this))->register(); - } + public function vendor($vendor = 'wpbones'): string + { + return "{$this->baseUri}/vendor/{$vendor}"; + } - protected function getOptionsAttribute(): WordPressOption - { - if (is_null($this->_options)) { - $this->_options = new WordPressOption($this); + /** + * Gets the value of an environment variable. Supports boolean, empty and null. + * + * @param string $key + * @param mixed $default + * + * @return mixed + */ + public function env($key, $default = null) + { + return wpbones_env($key, $default); } - return $this->_options; - } + /** + * Return an instance of View/Contract. + * + * @param null $key Optional. Default null. + * @param null $data Optional. Default null. + * + * @return View + */ + public function view($key = null, $data = []): View + { + $view = new View($this, $key, $data); - protected function getRequestAttribute(): Request - { - if (is_null($this->_request)) { - $this->_request = new Request(); + return $view; } - return $this->_request; - } + public function getPageUrl($pageSlug): string + { + return add_query_arg(['page' => $pageSlug], admin_url('admin.php')); + } - protected function getPluginBasenameAttribute(): string - { - return plugin_basename($this->file); - } + public function provider($name) + { + if (in_array($name, array_keys($this->provides))) { + return $this->provides[$name]; + } - protected function getCssAttribute(): string - { - return "{$this->baseUri}/public/css"; - } + return null; + } - protected function getJsAttribute(): string - { - return "{$this->baseUri}/public/js"; - } + /** + * Helper method to load (enqueue) styles. + * + * For your convenience, the params $filename may be an array of file. + * + * @param string|array $filename Filename + * @param array $deps Optional. Dependencies array + * @param null $version Optional. Default plugin version + */ + public function css($filename, $deps = [], $version = null) + { + $filenames = (array)$filename; + + foreach ($filenames as $file) { + wp_enqueue_style( + $this->slug . Str::slug($file), + $this->css . '/' . $file, + (array)$deps, + $version ?? $this->Version + ); + } + } - protected function getAppsAttribute(): string - { - return "{$this->baseUri}/public/apps"; - } + /** + * Helper method to load (enqueue) styles. + * + * For your convenience, the params $filename may be an array of file. + * + * @param string|array $filename Filenames + * @param array $deps Optional. Dependencies array + * @param null $version Optional. Default plugin version + * @param bool $footer Optional. Load on footer. Default true + */ + public function js($filename, $deps = [], $version = null, $footer = true) + { + $filenames = (array)$filename; + + foreach ($filenames as $file) { + wp_enqueue_script( + $this->slug . Str::slug($file), + WPKirk()->js . '/' . $file, + (array)$deps, + $version ?? $this->Version, + $footer + ); + } + } - protected function getImagesAttribute(): string - { - return "{$this->baseUri}/public/images"; - } - - public function __get($name) - { - if ($this->hasGetMutator($name)) { - return $this->mutateAttribute($name); - } - - if (in_array($name, array_keys($this->pluginData))) { - return $this->pluginData[$name]; - } - } - - public function set_screen_option($status, $option, $value) - { - if (in_array($option, array_values($this->config('plugin.screen_options', [])))) { - return $value; - } - - return $status; - } - - /** - * Get / set the specified configuration value. - * - * If an array is passed as the key, we will assume you want to set an array of values. - * - * @param array|string $key - * @param mixed $default - * - * @return mixed - */ - public function config($key = null, $default = null) - { - if (is_null($key)) { - return []; - } - - $parts = explode('.', $key); - - $filename = "{$parts[0]}.php"; - $key = $parts[1] ?? null; - - $array = include "{$this->basePath}/config/{$filename}"; - - if (is_null($key)) { - return $array; - } - - unset($parts[0]); - - foreach ($parts as $segment) { - if (!is_array($array) || !array_key_exists($segment, $array)) { - return wpbones_value($default); - } - - $array = $array[$segment]; - } - - return $array; - } - - /** - * Get the base path of the plugin installation. - * - * @return string - */ - public function getBasePath(): string - { - return $this->basePath; - } - - /** - * Return the absolute URL for the installation plugin. - * - * @return string - */ - public function getBaseUri(): string - { - return $this->baseUri; - } - - public function vendor($vendor = 'wpbones'): string - { - return "{$this->baseUri}/vendor/{$vendor}"; - } - - /** - * Gets the value of an environment variable. Supports boolean, empty and null. - * - * @param string $key - * @param mixed $default - * - * @return mixed - */ - public function env($key, $default = null) - { - return wpbones_env($key, $default); - } - - /** - * Return an instance of View/Contract. - * - * @param null $key Optional. Default null. - * @param null $data Optional. Default null. - * - * @return \WPKirk\WPBones\View\View - */ - public function view($key = null, $data = []): View - { - $view = new View($this, $key, $data); - - return $view; - } - - public function getPageUrl($pageSlug): string - { - return add_query_arg(['page' => $pageSlug], admin_url('admin.php')); - } - - public function provider($name) - { - if (in_array($name, array_keys($this->provides))) { - return $this->provides[$name]; - } - - return null; - } - - /** - * Helper method to load (enqueue) styles. - * - * For your convenience, the params $filename may be an array of file. - * - * @param string|array $filename Filename - * @param array $deps Optional. Dependencies array - * @param null $version Optional. Default plugin version - */ - public function css($filename, $deps = [], $version = null) - { - $filenames = (array) $filename; - - foreach ($filenames as $file) { - wp_enqueue_style( - $this->slug . Str::slug($file), - $this->css . '/' . $file, - (array) $deps, - $version ?? $this->Version - ); - } - } - - /* - |-------------------------------------------------------------------------- - | WordPress actions & filter - |-------------------------------------------------------------------------- - | - | When a plugin starts we will use some useful actions and filters. - | - */ - - /** - * Helper method to load (enqueue) styles. - * - * For your convenience, the params $filename may be an array of file. - * - * @param string|array $filename Filenames - * @param array $deps Optional. Dependencies array - * @param null $version Optional. Default plugin version - * @param bool $footer Optional. Load on footer. Default true - */ - public function js($filename, $deps = [], $version = null, $footer = true) - { - $filenames = (array) $filename; - - foreach ($filenames as $file) { - wp_enqueue_script( - $this->slug . Str::slug($file), - WPKirk()->js . '/' . $file, - (array) $deps, - $version ?? $this->Version, - $footer - ); - } - } - - /** - * Called when a plugin is updated; `upgrader_post_install` - * - * @param $response - * @param $hook_extra - * @param $result - * - * @return mixed - */ - public function upgrader_post_install($response, $hook_extra, $result) - { - // Check if the action is an update for a plugin - if (isset($hook_extra['plugin'])) { - // Verify if the updated plugin is the specific one - if ($hook_extra['plugin'] == plugin_basename($this->file)) { - // Call the update function - // include your own activation - $updated = include_once "{$this->basePath}/plugin/updated.php"; + /** + * Called when a plugin is updated; `upgrader_post_install` + * + * @param $response + * @param $hook_extra + * @param $result + * + * @return mixed + */ + public function upgrader_post_install($response, $hook_extra, $result) + { + // Check if the action is an update for a plugin + if (isset($hook_extra['plugin'])) { + // Verify if the updated plugin is the specific one + if ($hook_extra['plugin'] == plugin_basename($this->file)) { + // Call the update function + // include your own activation + $updated = include_once "{$this->basePath}/plugin/updated.php"; + + // updates/align the plugin options + $this->options->delta(); + + // migrations + foreach (glob("{$this->basePath}/database/migrations/*.php") as $filename) { + $instance = include $filename; + } + + // seeders + foreach (glob("{$this->basePath}/database/seeders/*.php") as $filename) { + $instance = include $filename; + } + } + } + return $response; + } + + /** + * Called when a plugin is activated; `register_activation_hook()` + * + */ + public function activation() + { // updates/align the plugin options $this->options->delta(); + // include your own activation + $activation = include_once "{$this->basePath}/plugin/activation.php"; + // migrations foreach (glob("{$this->basePath}/database/migrations/*.php") as $filename) { - $instance = include $filename; + $instance = include $filename; } // seeders foreach (glob("{$this->basePath}/database/seeders/*.php") as $filename) { - $instance = include $filename; + $instance = include $filename; } - } - } - - return $response; - } - - - /** - * Called when a plugin is activated; `register_activation_hook()` - * - */ - public function activation() - { - // updates/align the plugin options - $this->options->delta(); - - // include your own activation - $activation = include_once "{$this->basePath}/plugin/activation.php"; - - // migrations - foreach (glob("{$this->basePath}/database/migrations/*.php") as $filename) { - $instance = include $filename; - } - - // seeders - foreach (glob("{$this->basePath}/database/seeders/*.php") as $filename) { - $instance = include $filename; - } - } - - /** - * Return the list of classes in a PHP file. - * - * @param string $filename A PHP Filename file. - * - * @return array|bool - * - * @suppress PHP0415 - */ - private function getFileClasses($filename) - { - $code = file_get_contents($filename); - - if (empty($code)) { - return false; - } - - $classes = []; - $tokens = token_get_all($code); - $count = count($tokens); - for ($i = 2; $i < $count; $i++) { - if ($tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) { - $class_name = $tokens[$i][1]; - $classes[] = $class_name; - } - } - - return $classes; - } - - /** - * Called when a plugin is deactivated; `register_deactivation_hook()` - * - */ - public function deactivation() - { - $deactivation = include_once "{$this->basePath}/plugin/deactivation.php"; - } - - /** - * Fires after WordPress has finished loading but before any headers are sent. - * - * Most of WP is loaded at this stage, and the user is authenticated. WP continues - * to load on the init hook that follows (e.g. widgets), and many plugins instantiate - * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.). - * - * If you wish to plug an action once WP is loaded, use the wp_loaded hook below. - * - */ - public function init() - { - // Here we are going to init Service Providers - - // Custom post types Service Provider - $custom_post_types = $this->config('plugin.custom_post_types', []); - foreach ($custom_post_types as $className) { - $object = new $className($this); - $object->register(); - $this->provides[$className] = $object; - } - - // Custom taxonomy type Service Provider - $custom_taxonomy_types = $this->config('plugin.custom_taxonomy_types', []); - foreach ($custom_taxonomy_types as $className) { - $object = new $className($this); - $object->register(); - $this->provides[$className] = $object; - } - - // Shortcodes Service Provider - $shortcodes = $this->config('plugin.shortcodes', []); - foreach ($shortcodes as $className) { - $object = new $className($this); - $object->register(); - $this->provides[$className] = $object; - } - - // Ajax Service Provider - if ($this->isAjax()) { - $ajax = $this->config('plugin.ajax', []); - foreach ($ajax as $className) { - $object = new $className($this); - $object->register(); - $this->provides[$className] = $object; - } - } - - // Custom service provider - $providers = $this->config('plugin.providers', []); - foreach ($providers as $className) { - $object = new $className($this); - $object->register(); - $this->provides[$className] = $object; - } - } - - /** - * Return TRUE if an Ajax called - * - * @return bool - */ - public function isAjax(): bool - { - if (defined('DOING_AJAX')) { - return true; - } - if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { - return true; - } - - return false; - } - - public function log() - { - return $this->provides['Log']; - } - - // -- private - - /** - * Fires before the administration menu loads in the admin. - */ - public function admin_menu() - { - // register the admin menu - (new AdminMenuProvider($this))->register(); - - // register the admin custom pages - (new AdminRouteProvider($this))->register(); - - // register the custom pages via folder - (new PageProvider($this))->register(); - } - - public function widgets_init() - { - global $wp_widget_factory; - - $widgets = $this->config('plugin.widgets', []); - - foreach ($widgets as $className) { - //register_widget($className); - $wp_widget_factory->widgets[$className] = new $className($this); - } - } - - /** - * Description - * - * @param $routes - * @return Closure|null - */ - public function getCallableHook($routes) - { - // get the http request verb - $verb = $this->request->method; - - if (isset($routes['resource'])) { - $methods = [ - 'get' => 'index', - 'post' => 'store', - 'put' => 'update', - 'patch' => 'update', - 'delete' => 'destroy', - ]; - - $controller = $routes['resource']; - $method = $methods[$verb]; - } - // by single verb and controller@method - else { - if (isset($routes[$verb])) { - [$controller, $method] = Str::parseCallback($routes[$verb]); - } - // default "get" - else { - if (isset($routes['get'])) { - [$controller, $method] = Str::parseCallback($routes['get']); + } + + /** + * Called when a plugin is deactivated; `register_deactivation_hook()` + * + */ + public function deactivation() + { + $deactivation = include_once "{$this->basePath}/plugin/deactivation.php"; + } + + /** + * Fires after WordPress has finished loading but before any headers are sent. + * + * Most of WP is loaded at this stage, and the user is authenticated. WP continues + * to load on the init hook that follows (e.g. widgets), and many plugins instantiate + * themselves on it for all sorts of reasons (e.g. they need a user, a taxonomy, etc.). + * + * If you wish to plug an action once WP is loaded, use the wp_loaded hook below. + * + */ + public function init() + { + // Here we are going to init Service Providers + + // Custom post types Service Provider + $custom_post_types = $this->config('plugin.custom_post_types', []); + foreach ($custom_post_types as $className) { + $object = new $className($this); + $object->register(); + $this->provides[$className] = $object; + } + + // Custom taxonomy type Service Provider + $custom_taxonomy_types = $this->config('plugin.custom_taxonomy_types', []); + foreach ($custom_taxonomy_types as $className) { + $object = new $className($this); + $object->register(); + $this->provides[$className] = $object; + } + + // Shortcodes Service Provider + $shortcodes = $this->config('plugin.shortcodes', []); + foreach ($shortcodes as $className) { + $object = new $className($this); + $object->register(); + $this->provides[$className] = $object; + } + + // Ajax Service Provider + if ($this->isAjax()) { + $ajax = $this->config('plugin.ajax', []); + foreach ($ajax as $className) { + $object = new $className($this); + $object->register(); + $this->provides[$className] = $object; + } + } + + // Custom service provider + $providers = $this->config('plugin.providers', []); + foreach ($providers as $className) { + $object = new $className($this); + $object->register(); + $this->provides[$className] = $object; } - } } - if (isset($controller) && isset($method)) { - return function () use ($controller, $method) { - $className = "WPKirk\\Http\\Controllers\\{$controller}"; - $instance = new $className(); + /** + * Return TRUE if an Ajax called + * + * @return bool + */ + public function isAjax(): bool + { + if (defined('DOING_AJAX')) { + return true; + } + if (isset($_SERVER['HTTP_X_REQUESTED_WITH']) && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest') { + return true; + } + + return false; + } + + public function log() + { + return $this->provides['Log']; + } + + /* + |-------------------------------------------------------------------------- + | WordPress actions & filter + |-------------------------------------------------------------------------- + | + | When a plugin starts we will use some useful actions and filters. + | + */ + + /** + * Fires before the administration menu loads in the admin. + */ + public function admin_menu() + { + // register the admin menu + (new AdminMenuProvider($this))->register(); + + // register the admin custom pages + (new AdminRouteProvider($this))->register(); + + // register the custom pages via folder + (new PageProvider($this))->register(); + } - if (method_exists($instance, 'render')) { - return $instance->render("{$method}"); + public function widgets_init() + { + global $wp_widget_factory; + + $widgets = $this->config('plugin.widgets', []); + + foreach ($widgets as $className) { + //register_widget($className); + $wp_widget_factory->widgets[$className] = new $className($this); } - }; } - return null; - } + /** + * Description + * + * @param $routes + * @return Closure|null + */ + public function getCallableHook($routes) + { + // get the http request verb + $verb = $this->request->method; + + if (isset($routes['resource'])) { + $methods = [ + 'get' => 'index', + 'post' => 'store', + 'put' => 'update', + 'patch' => 'update', + 'delete' => 'destroy', + ]; + + $controller = $routes['resource']; + $method = $methods[$verb]; + } // by single verb and controller@method + else { + if (isset($routes[$verb])) { + [$controller, $method] = Str::parseCallback($routes[$verb]); + } // default "get" + else { + if (isset($routes['get'])) { + [$controller, $method] = Str::parseCallback($routes['get']); + } + } + } + + if (isset($controller) && isset($method)) { + return function () use ($controller, $method) { + $className = "WPKirk\\Http\\Controllers\\{$controller}"; + $instance = new $className(); + + if (method_exists($instance, 'render')) { + return $instance->render("{$method}"); + } + }; + } + + return null; + } + + protected function getOptionsAttribute(): WordPressOption + { + if (is_null($this->_options)) { + $this->_options = new WordPressOption($this); + } + + return $this->_options; + } + + protected function getRequestAttribute(): Request + { + if (is_null($this->_request)) { + $this->_request = new Request(); + } + + return $this->_request; + } + + protected function getPluginBasenameAttribute(): string + { + return plugin_basename($this->file); + } + + protected function getCssAttribute(): string + { + return "{$this->baseUri}/public/css"; + } + + protected function getJsAttribute(): string + { + return "{$this->baseUri}/public/js"; + } + + // -- private + + protected function getAppsAttribute(): string + { + return "{$this->baseUri}/public/apps"; + } + + protected function getImagesAttribute(): string + { + return "{$this->baseUri}/public/images"; + } + + /** + * Return the list of classes in a PHP file. + * + * @param string $filename A PHP Filename file. + * + * @return array|bool + * + * @suppress PHP0415 + */ + private function getFileClasses($filename) + { + $code = file_get_contents($filename); + + if (empty($code)) { + return false; + } + + $classes = []; + $tokens = token_get_all($code); + $count = count($tokens); + for ($i = 2; $i < $count; $i++) { + if ($tokens[$i - 2][0] == T_CLASS && $tokens[$i - 1][0] == T_WHITESPACE && $tokens[$i][0] == T_STRING) { + $class_name = $tokens[$i][1]; + $classes[] = $class_name; + } + } + + return $classes; + } }