Created
September 3, 2011 20:04
-
-
Save kgilden/1191703 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/DataProvider/DataProvider.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\DataProvider; | |
/** | |
* An abstract implementation of the DataProviderInterface. It is not necessary | |
* to extend this class, just implement the DataProviderInterface. | |
*/ | |
abstract class DataProvider implements DataProviderInterface | |
{ | |
/** | |
* This is just a stub method. You probably want to | |
* write your own method for more complex data retrieval | |
* (such as getting a row by id from a database). | |
* | |
* {@inheritDoc} | |
*/ | |
public function getById($id) | |
{ | |
return array('id' => $id); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/DataProvider/DataProviderInterface.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\DataProvider; | |
/** | |
* A data provider interface. | |
*/ | |
interface DataProviderInterface | |
{ | |
/** | |
* Get some data by id. The implementation is totally up to you, where | |
* the data is retrieved from. | |
* | |
* @param integer $id Resource id | |
* @param string $type Resource type (e.g "link", "media" etc.) | |
* @return array An associative array consisting the data. | |
* For example a link resource should return: | |
* array | |
* ( | |
* 'id' => $id, | |
* 'href' => 'http://example.com' | |
* 'text' => 'Link title' | |
* ) | |
*/ | |
function findById($id, $type); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /example.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
/** | |
* This is just an example of how it all comes together. | |
*/ | |
use Gilden\Parser\TagParser; | |
use Gilden\DataProvider\DataProviderInterface; | |
function __autoload($name) | |
{ | |
$name = str_replace('\\', '/', $name); | |
require_once __DIR__.'/lib/'.$name.'.php'; | |
} | |
/** | |
* We need to implement the DataProviderInterface for the sake of this | |
* example. This is the place, where the TagProvider gets the data | |
* for the tags. | |
*/ | |
class DataProvider implements DataProviderInterface | |
{ | |
public function findById($id, $type) | |
{ | |
if($type === TagParser::TYPE_LINK) | |
{ | |
return array('href' => 'google.com', 'content' => 'Google'); | |
} | |
elseif($type === TagParser::TYPE_MEDIA) | |
{ | |
return array('src' => 'example.swf'); | |
} | |
} | |
} | |
$dp = new DataProvider(); | |
$parser = new TagParser($dp); | |
$parser->setText('This is [link id=1]'); | |
echo $parser->getHtml(); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/Parser/InvalidTypeException.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\Parser; | |
/** | |
* This exception will be thrown, if a tag is of unkown type. | |
*/ | |
class InvalidTypeException extends \Exception | |
{ | |
/** | |
* @param string $type | |
*/ | |
public function __construct($type) | |
{ | |
parent::__construct("'$type' is not a valid tag type"); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/Parser/TagParser.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\Parser; | |
use Gilden\DataProvider\DataProviderInterface; | |
/** | |
* Tag parser class. | |
*/ | |
class TagParser implements TagParserInterface | |
{ | |
const TAG_PATTERN = '/\[.*?\]/'; | |
// Tag types | |
const TYPE_MEDIA = 'media'; | |
const TYPE_LINK = 'link'; | |
/** | |
* Data provider | |
*/ | |
protected $dp; | |
/** | |
* Rendered html version | |
* | |
* @var string $html | |
*/ | |
protected $html; | |
/** | |
* @var boolean $rendered | |
*/ | |
protected $rendered; | |
/** | |
* Raw input text to be parsed | |
* | |
* @var string $text | |
*/ | |
protected $text; | |
/** | |
* Constructor. | |
*/ | |
public function __construct(DataProviderInterface $dp) | |
{ | |
$this->rendered = false; | |
$this->dp = $dp; | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public function getHtml() | |
{ | |
if(!$this->rendered) | |
{ | |
$this->render(); | |
} | |
return $this->html; | |
} | |
/** | |
* {@inheritDoc} | |
*/ | |
public function setText($text) | |
{ | |
$this->text = $text; | |
$this->rendered = false; | |
return $this; | |
} | |
/** | |
* Gets parameters from a tag. Right now this method is rather | |
* naive. It assumes the tag no syntax errors. Valid tags include: | |
* | |
* - [type attr1=val1 attr2='val 2'] | |
* | |
* These examples are not valid tags and might make this method | |
* return unexpected results | |
* | |
* - [] - no params at all | |
* - [attr1=val1] - missing type | |
* - [type attr1='val1] - wrong use of quotes | |
* - [type attr1=val 1] - missing quotes | |
* | |
* @param string $tag | |
* @return array $params An array of all the parameters | |
*/ | |
protected function getParameters($tag) | |
{ | |
// remove "[" and "]" | |
$tag = substr($tag, 1, -1); | |
$params = array(); | |
$bits = explode(' ', $tag); | |
$params['type'] = array_shift($bits); | |
$processed = array(); | |
$j = 0; | |
foreach($bits as $i => $bit) | |
{ | |
$bit = explode('=', $bit); | |
// Remove quotes from the value. | |
if(isset($bit[1]) | |
&& $bit[1][0] === "'" | |
&& $bit[1][strlen($bit[1]) - 1] === "'") | |
{ | |
$bit[1] = substr($bit[1], 1, -1); | |
} | |
if($bit[0][strlen($bit[0]) - 1] === "'") | |
{ | |
// The bit is the end of a quoted value. | |
$processed[$j-1]['value'] .= ' '.substr($bit[0], 0, -1); | |
} | |
elseif($bit[0][0] === "'") | |
{ | |
// The bit is the beginning of a quoted value. | |
echo 'beginning'; | |
$processed[$j-1]['value'] = substr($bit[0], 1); | |
} | |
elseif(!isset($bit[1])) | |
{ | |
// The bit is a continuation of the previous bit. | |
$processed[$j-1]['value'] .= ' '.$bit[0]; | |
} | |
else | |
{ | |
if($bit[1][0] === "'") | |
{ | |
$bit[1] = substr($bit[1], 1); | |
} | |
$processed[$j++] = array('name' => $bit[0], 'value' => $bit[1]); | |
} | |
} | |
foreach($processed as $param) | |
{ | |
$params[$param['name']] = $param['value']; | |
} | |
return $params; | |
} | |
/** | |
* Render the raw text template into html | |
*/ | |
protected function render() | |
{ | |
$this->rendered = true; | |
$this->html = preg_replace_callback(self::TAG_PATTERN, array($this, 'replace'), $this->text); | |
} | |
/** | |
* Replace a tag with a html element | |
* | |
* @param string $tag | |
*/ | |
protected function replace($tag) | |
{ | |
$params = $this->getParameters($tag[0]); | |
if(isset($params['id'])) | |
{ | |
$id = $params['id']; | |
unset($params['id']); | |
$params_external = $this->dp->findById($id, $params['type']); | |
if(!is_array($params_external)) | |
{ | |
throw new \Exception(sprintf('Expected array, got %s instead', gettype($params_external))); | |
} | |
$params = array_merge($params, $params_external); | |
} | |
switch($params['type']) | |
{ | |
case self::TYPE_MEDIA: | |
return $this->renderMedia($params); | |
case self::TYPE_LINK: | |
return $this->renderLink($params); | |
default: | |
throw new InvalidTypeException($params['type']); | |
} | |
} | |
/** | |
* Render a HTML link tag | |
* | |
* @param array $params | |
* @return string $media | |
*/ | |
protected function renderLink(array $params) | |
{ | |
$specials = array('content', 'type'); | |
if(!isset($params['href'])) | |
{ | |
return '[Error! Link tag is missing a ´href´ parameter!]'; | |
} | |
$link = '<a'; | |
$attr = $this->renderAttributes($params, $specials); | |
if(isset($attr[0])) | |
{ | |
$link .= $attr; | |
} | |
$link .= '>'.(isset($params['content']) ? $params['content'] : $params['href']).'</a>'; | |
return $link; | |
} | |
/** | |
* Render a flash object tag. This does not work in IE. You must modify | |
* this function to have it output html similar to | |
* http://kb2.adobe.com/cps/415/tn_4150.html#main_Add_the_OBJECT_tag_manually | |
* | |
* @param array $params | |
* @return string $media | |
*/ | |
protected function renderMedia(array $params) | |
{ | |
$specials = array('src', 'type'); | |
if(!isset($params['src'])) | |
{ | |
return '[Error! Media tag is missing a ´src´ parameter!]'; | |
} | |
$media = '<object'; | |
$attr = $this->renderAttributes($params, $specials); | |
if(isset($attr[0])) | |
{ | |
$media .= $attr; | |
} | |
$media .= '><param name="movie" value="'.$params['src'].'"></param></object>'; | |
return $media; | |
} | |
/** | |
* Render attributes. | |
* | |
* @param array $params Attributes to render | |
* @param array $ignore All attributes in this array will be ignored | |
* @return string $ret Attributes (' foo="bar" bar="foo" ...') | |
*/ | |
protected function renderAttributes(array $params, array $ignore = array()) | |
{ | |
$ret = ''; | |
foreach($params as $key => $param) | |
{ | |
if(in_array($key, $ignore)) | |
{ | |
continue; | |
} | |
$ret .= ' '.$key.sprintf('="%s"', $param); | |
} | |
return $ret; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/Parser/TagParserInterface.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\Parser; | |
interface TagParserInterface | |
{ | |
/** | |
* Set the text for rendering. | |
* | |
* @param string $text | |
* @return TagParserInterface | |
*/ | |
function setText($text); | |
/** | |
* Get the rendered html. | |
* | |
* @param string Rendered html | |
*/ | |
function getHtml(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// /lib/Gilden/Tests/TagParserTest.php | |
/** | |
* Copyright (C) 2011 by K. Gilden | |
* | |
* Permission is hereby granted, free of charge, to any person obtaining a copy | |
* of this software and associated documentation files (the "Software"), to deal | |
* in the Software without restriction, including without limitation the rights | |
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
* copies of the Software, and to permit persons to whom the Software is | |
* furnished to do so, subject to the following conditions: | |
* | |
* The above copyright notice and this permission notice shall be included in | |
* all copies or substantial portions of the Software. | |
* | |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
* THE SOFTWARE. | |
*/ | |
namespace Gilden\Tests\Parser\TagParser; | |
use Gilden\DataProvider\DataProvider; | |
use Gilden\Parser\TagParser; | |
/** | |
* This is the basic unit test to test the tag parser. | |
*/ | |
class TagParserText extends \PHPUnit_Framework_TestCase | |
{ | |
public function testGetHtmlContainingLink() | |
{ | |
$parser = new TagParser($this->getLinkMock()); | |
$text = "This is [link id=1], [link id=1 class='foo bar']"; | |
$expected = 'This is <a href="http://example.com">example</a>, <a class="foo bar" href="http://example.com">example</a>'; | |
$parser->setText($text); | |
$this->assertEquals($expected, $parser->getHtml()); | |
} | |
public function testGetHtmlContainingObject() | |
{ | |
$parser = new TagParser($this->getMediaMock()); | |
$text = 'Check this swf: [media id=1 width=660 height=440]'; | |
$expected = 'Check this swf: <object width="660" height="440"><param name="movie" value="movie_name.swf"></param></object>'; | |
$parser->setText($text); | |
$this->assertEquals($expected, $parser->getHtml()); | |
} | |
/** | |
* @expectedException \Gilden\Parser\InvalidTypeException | |
*/ | |
public function testGetHtmlContainingInvalid() | |
{ | |
$parser = new TagParser($this->getLinkMock()); | |
$text = "Invalid type [invalid id=1 foo='bar foo']"; | |
$parser->setText($text)->getHtml(); | |
} | |
private function getLinkMock() | |
{ | |
$return_data = array | |
( | |
'href' => 'http://example.com', | |
'content' => 'example' | |
); | |
$mock = $this->getMock('\Gilden\DataProvider\DataProvider', array('getById')); | |
$mock->expects($this->any()) | |
->method('getById') | |
->will($this->returnValue($return_data)); | |
return $mock; | |
} | |
private function getMediaMock() | |
{ | |
$return_data = array | |
( | |
'src' => 'movie_name.swf' | |
); | |
$mock = $this->getMock('\Gilden\DataProvider\DataProvider', array('getById')); | |
$mock->expects($this->any()) | |
->method('getById') | |
->will($this->returnValue($return_data)); | |
return $mock; | |
} | |
} | |
function autoload($name) | |
{ | |
$name = str_replace('\\', '/', $name); | |
require_once __DIR__.'/../../../'.$name.'.php'; | |
} | |
spl_autoload_register(__NAMESPACE__.'\autoload'); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment