Skip to content

Commit

Permalink
Merge pull request #453 from grasmash/yaml-support
Browse files Browse the repository at this point in the history
Abstracting FileParser to use factory class, adding yaml config support.
  • Loading branch information
mrook committed Aug 28, 2015
2 parents d10d924 + 70a3c74 commit 4136999
Show file tree
Hide file tree
Showing 18 changed files with 622 additions and 106 deletions.
64 changes: 64 additions & 0 deletions classes/phing/system/io/FileParserFactory.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/
include_once 'phing/system/io/IniFileParser.php';
include_once 'phing/system/io/FileParserFactoryInterface.php';
include_once 'phing/system/io/YamlFileParser.php';

/**
* The factory to create fileParsers based on extension name from
* PhingFile->getFileExtension()
*
* @author Mike Lohmann <mike.lohmann@deck36.de>
* @package phing.system.io
*/
class FileParserFactory implements FileParserFactoryInterface
{
/**
* @const string
*/
const YAMLFILEEXTENSION = 'yml';

/**
* @const string
*/
const YAMLFILEEXTENSIONLONG = 'yaml';

/**
* {@inheritDoc}
*/
public function createParser($fileExtension)
{
if (phpversion() >= 5.3) {
switch ($fileExtension) {
case self::YAMLFILEEXTENSION:
case self::YAMLFILEEXTENSIONLONG:
$fileParser = new YamlFileParser();
break;
default:
$fileParser = new IniFileParser();
}
} else {
$fileParser = new IniFileParser();
}

return $fileParser;
}
}
38 changes: 38 additions & 0 deletions classes/phing/system/io/FileParserFactoryInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/

/**
* This interface can be used to implement a fileParserFactory to create FileParsers based on config.
* Currently it is used in the PropertyTask to deliver the correct parser based on filetype.
*
* @author Mike Lohmann <mike.lohmann@deck36.de>
* @package phing.system.io
*/
interface FileParserFactoryInterface
{
/**
* Based on the $name a parser will be returned.
*
* @param string $fileExtension
* @return FileParserInterface
*/
public function createParser($fileExtension);
}
39 changes: 39 additions & 0 deletions classes/phing/system/io/FileParserInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/

/**
* This interface can be used to implement a fileParser for property files.
* For example: You can implement a .ini-Fileparser or .yaml/.xml/.php.
*
* @author Mike Lohmann <mike.lohmann@deck36.de>
* @package phing.system.io
*/
interface FileParserInterface
{
/**
* Builds an array from the given (ini) file and returns it.
*
* @param $file
* @return array
* @throws IOException
*/
public function parseFile(PhingFile $file);
}
86 changes: 86 additions & 0 deletions classes/phing/system/io/IniFileParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/
include_once 'phing/system/io/FileParserInterface.php';

/**
* Implements an IniFileParser. The logic is coming from th Properties.php, but I don't know who's the author.
*
* FIXME
* - Add support for arrays (separated by ',')
*
* @author Mike Lohmann <mike.lohmann@deck36.de>
* @package phing.system.io
*/
class IniFileParser implements FileParserInterface
{
/**
* {@inheritDoc}
*/
public function parseFile(PhingFile $file)
{
if (($lines = @file($file)) === false) {
throw new IOException("Unable to parse contents of $file");
}

// concatenate lines ending with backslash
$linesCount = count($lines);
for ($i = 0; $i < $linesCount; $i++) {
if (substr($lines[$i], -2, 1) === '\\') {
$lines[$i + 1] = substr($lines[$i], 0, -2) . ltrim($lines[$i + 1]);
$lines[$i] = '';
}
}

$properties = array();
foreach ($lines as $line) {
// strip comments and leading/trailing spaces
$line = trim(preg_replace("/\s+[;#]\s.+$/", "", $line));

if (empty($line) || $line[0] == ';' || $line[0] == '#') {
continue;
}

$pos = strpos($line, '=');
$property = trim(substr($line, 0, $pos));
$value = trim(substr($line, $pos + 1));
$properties[$property] = $this->inVal($value);

} // for each line

return $properties;
}

/**
* Process values when being read in from properties file.
* does things like convert "true" => true
* @param string $val Trimmed value.
* @return mixed The new property value (may be boolean, etc.)
*/
protected function inVal($val)
{
if ($val === "true") {
$val = true;
} elseif ($val === "false") {
$val = false;
}
return $val;
}
}
9 changes: 9 additions & 0 deletions classes/phing/system/io/PhingFile.php
Original file line number Diff line number Diff line change
Expand Up @@ -287,6 +287,15 @@ public function isAbsolute()
return ($this->prefixLength !== 0);
}

/**
* Returns the file extension for a given file. For example test.php would be returned as php.
*
* @return string The name of the extension.
*/
public function getFileExtension()
{
return pathinfo((string) $this->getAbsolutePath(), PATHINFO_EXTENSION);
}

/**
* Returns the absolute pathname string of this abstract pathname.
Expand Down
90 changes: 90 additions & 0 deletions classes/phing/system/io/YamlFileParser.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
<?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information please see
* <http://phing.info>.
*/
include_once 'phing/system/io/FileParserInterface.php';

/**
* Implements a YamlFileParser to parse yaml-files as array.
*
* @author Mike Lohmann <mike.lohmann@deck36.de>
* @package phing.system.io
*/
class YamlFileParser implements FileParserInterface
{
/**
* {@inheritDoc}
*/
public function parseFile(PhingFile $file)
{
if (!$file->canRead()) {
throw new IOException("Unable to read file: " . $file);
}

try {
// We load the Yaml class without the use of namespaces to prevent
// parse errors in PHP 5.2.
$parser = '\Symfony\Component\Yaml\Parser';
$properties = $parser->parse($file->getAbsolutePath());
} catch (Exception $e) {
if (is_a($e, '\Symfony\Component\Yaml\Exception\ParseException')) {
throw new IOException("Unable to parse contents of " . $file . ": " . $e->getMessage());
}
throw $e;
}

$flattenedProperties = $this->flattenArray($properties);
foreach ($flattenedProperties as $key => $flattenedProperty) {
if (is_array($flattenedProperty)) {
$flattenedProperties[$key] = implode(',', $flattenedProperty);
}
}

return $flattenedProperties;
}

/**
* Flattens an array to key => value.
* @todo: milo - 20142901 - If you plan to extend phing and add a new fileparser, please move this to an abstract
* class.
*
* @param array $arrayToFlatten
*/
private function flattenArray(array $arrayToFlatten, $separator = '.', $flattenedKey = '')
{
$flattenedArray = array();
foreach ($arrayToFlatten as $key => $value) {
$tmpFlattendKey = (!empty($flattenedKey) ? $flattenedKey.$separator : '') . $key;
// only append next value if is array and is an associative array
if (is_array($value) && array_keys($value) !== range(0, count($value) - 1)) {
$flattenedArray = array_merge(
$flattenedArray,
$this->flattenArray(
$value,
$separator,
$tmpFlattendKey
)
);
} else {
$flattenedArray[$tmpFlattendKey] = $value;
}
}
return $flattenedArray;
}
}
Loading

0 comments on commit 4136999

Please sign in to comment.