Skip to content

Commit

Permalink
Initial commit.
Browse files Browse the repository at this point in the history
  • Loading branch information
wpscholar committed Mar 17, 2020
0 parents commit 7aa4435
Show file tree
Hide file tree
Showing 8 changed files with 508 additions and 0 deletions.
12 changes: 12 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# Config

[![Latest Stable Version](https://poser.pugx.org/wp-forge/config/v/stable)](https://packagist.org/packages/wp-forge/helpers)
[![Total Downloads](https://poser.pugx.org/wp-forge/config/downloads)](https://packagist.org/packages/wp-forge/helpers)
[![License](https://poser.pugx.org/wp-forge/config/license)](https://packagist.org/packages/wp-forge/helpers)

A configuration file management tool.

## Install
```$xslt
composer require wp-forge/config
```
20 changes: 20 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"name": "wp-forge/config",
"description": "A configuration file management tool.",
"license": "GPL-2.0-or-later",
"authors": [
{
"name": "Micah Wood",
"email": "[email protected]"
}
],
"autoload": {
"psr-4": {
"WP_Forge\\Config\\": "includes"
}
},
"require": {
"wp-forge/data-store": "^1.0",
"mustangostang/spyc": "^0.6.3"
}
}
202 changes: 202 additions & 0 deletions includes/ConfigFile.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,202 @@
<?php

namespace WP_Forge\Config;

use InvalidArgumentException;
use RuntimeException;
use WP_Forge\Config\Contracts\ConfigStrategy;
use WP_Forge\Config\Factory\ConfigStrategyFactory;
use WP_Forge\DataStore\DataStore;

/**
* Class ConfigFile
*
* @package WP_Forge\Config
*/
class ConfigFile extends DataStore {

/**
* Full path to the config file.
*
* @var string
*/
protected $file;

/**
* Directory path to the config file.
*
* @var string
*/
protected $path;

/**
* The strategy to use for transforming config data.
*
* @var ConfigStrategy
*/
protected $strategy;

/**
* Create a new instance of this class.
*
* @param string $file Full path to the config file.
*
* @return static
*/
public static function make( $file ) {
return new static( $file );
}

/**
* ConfigFile constructor.
*
* @param string $file Full path to the config file.
*/
public function __construct( $file ) {
$this->file = $file;
$this->path = dirname( $file );
$this->strategy = ConfigStrategyFactory::create( $file );
}

/**
* Check if the file exists.
*
* @return bool
*/
public function exists() {
return file_exists( $this->file );
}

/**
* Check if the file is readable.
*
* @return bool
*/
public function isReadable() {
return is_readable( $this->file );
}

/**
* Check if the file is writable.
*
* @return bool
*/
public function isWritable() {
return is_writable( $this->file );
}

/**
* Create the file.
*
* @return $this
*/
public function create() {

// Create any missing directories
if ( ! is_dir( $this->path ) ) {
if ( ! mkdir( $this->path, 0755, true ) ) {
throw new RuntimeException( sprintf( 'Unable to create directory: "%s"', $this->path ) );
}
}

// Create file if it doesn't exist
if ( ! $this->exists() ) {
if ( ! touch( $this->file ) ) {
throw new RuntimeException( sprintf( 'Unable to create file: "%s"', $this->file ) );
}
}

// Write the current config to file.
$this->update();

return $this;
}

/**
* Read the file. Loads content into the config data store.
*
* @return $this
*/
public function read() {
if (
! $this->exists() ||
! $this->isReadable() ||
! boolval( $contents = file_get_contents( $this->file ) )
) {
throw new RuntimeException( sprintf( 'Unable to read file: "%s"', $this->file ) );
}

$this->data = $this->strategy->parse( $contents );

return $this;
}

/**
* Write the in-memory config data to the file.
*
* @return $this
*/
public function update() {
if (
! $this->exists() ||
! $this->isWritable() ||
! boolval( file_put_contents( $this->file, $this->strategy->prepare( $this->data ) . PHP_EOL ) )
) {
throw new RuntimeException( sprintf( 'Unable to write to file: "%s"', $this->file ) );
}

return $this;
}

/**
* Delete the file.
*
* @return $this
*/
public function delete() {
if ( $this->exists() ) {
if ( ! unlink( $this->file ) ) {
throw new RuntimeException( sprintf( 'Unable to delete file: "%s"', $this->file ) );
};
}

return $this;
}

/**
* Magic method to provide read-only access to protected class properties.
*
* @param string $property
*
* @return mixed
*
* @throws \InvalidArgumentException
*/
public function __get( $property ) {
$method = "_{$property}";
if ( ! property_exists( $this, $property ) || ! method_exists( $this, $method ) ) {
throw new InvalidArgumentException( sprintf( 'Property %s does not exist', $property ) );
}

return $this->{$method}();
}

/**
* Get full file path to config file.
*
* @return string
*/
protected function _file() {
return $this->file;
}

/**
* Directory path to the config file.
*
* @return string
*/
protected function _path() {
return $this->path;
}

}
121 changes: 121 additions & 0 deletions includes/ConfigFinder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
<?php

namespace WP_Forge\Config;

use RuntimeException;

/**
* Class ConfigFinder
*
* @package WP_Forge\Config
*/
class ConfigFinder {

/**
* The config file names.
*
* @var array
*/
protected $names;

/**
* Whether or not to traverse up the directory tree.
*
* @var bool
*/
protected $traverse = true;

/**
* Returns a new instance.
*
* @param string|array $names The name(s) of the config file(s). Checked in order.
*
* @return ConfigFinder
*/
public static function searchFor( $names ) {
return new self( $names );
}

/**
* ConfigFinder constructor.
*
* @param string|array $names The name(s) of the config file(s). Checked in order.
*/
public function __construct( $names ) {
$this->names = is_array( $names ) ? $names : [ (string) $names ];
}

/**
* Change whether or not to traverse up the directory tree.
*
* @param $bool
*
* @return $this
*/
public function shouldTraverse( $bool ) {
$this->traverse = boolval( $bool );

return $this;
}

/**
* Find a config file, if one exists.
*
* @param string $path The directory from which to start looking.
*
* @return string|null The file path on success or null on failure.
*/
public function find( $path ) {
$found = null;

while ( is_readable( $path ) && is_null( $found ) && $path !== dirname( $this->getHomeDir() ) ) {
foreach ( $this->names as $name ) {
$file = $path . DIRECTORY_SEPARATOR . $name;
if ( file_exists( $file ) && is_readable( $file ) ) {
$found = $file;
break;
}
}
if ( ! $this->traverse ) {
break;
}
$path = dirname( $path );
}

return $found;
}

/**
* Find a config file, if one exists. Otherwise, throw an exception.
*
* @param string $path The directory from which to start looking.
*
* @return string The file path.
*
* @throws RuntimeException
*/
public function find_or_die( $path ) {
$found = $this->find( $path );
if ( is_null( $this->find( $path ) ) ) {
throw new RuntimeException( 'No config file found!' );
}

return $found;
}

/**
* Get the user's home directory.
*
* @return string
*/
protected function getHomeDir() {
$home = getenv( 'HOME' );
if ( ! $home ) {
// In Windows $HOME may not be defined
$home = getenv( 'HOMEDRIVE' ) . getenv( 'HOMEPATH' );
}

return rtrim( $home, '/\\' );
}

}
30 changes: 30 additions & 0 deletions includes/Contracts/ConfigStrategy.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?php

namespace WP_Forge\Config\Contracts;

/**
* Interface ConfigStrategy
*
* @package WP_Forge\Config\Contracts
*/
interface ConfigStrategy {

/**
* Parse the data from file contents.
*
* @param string $contents The raw file contents.
*
* @return array The structured data array.
*/
public function parse( $contents );

/**
* Prepare the data to be written to a file.
*
* @param array $data The structured data array.
*
* @return string The raw file contents.
*/
public function prepare( $data );

}
Loading

0 comments on commit 7aa4435

Please sign in to comment.