Skip to content

Commit

Permalink
Refactor to OOP using pimple as DI container.
Browse files Browse the repository at this point in the history
  • Loading branch information
cbenard committed Jul 31, 2015
1 parent faa5ec2 commit 66640d8
Show file tree
Hide file tree
Showing 14 changed files with 320 additions and 4 deletions.
2 changes: 1 addition & 1 deletion app.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
application: comicfeeds-1022
version: 2
version: 3
runtime: php55
api_version: 1
threadsafe: no
Expand Down
11 changes: 11 additions & 0 deletions classes/DilbertService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

class DilbertService extends GenericComicService {
public function __construct(FeedService $feedService, Logger $logger, StorageService $store) {
parent::__construct("dilbert_default", $feedService, $logger, $store);

$this->feed = "http://dilbert.com/feed.rss";
$this->pattern = '/data-image="(.+?)"/';
$this->entrySearchText = "Comic for ";
}
}
48 changes: 48 additions & 0 deletions classes/FeedService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
<?php

class FeedService {
private $log;

public function __construct(Logger $logger) {
$this->log = $logger;
}

public function fetchFeed($url) {
$doc = simplexml_load_file($url);
if ($doc === FALSE) {
throw new Exception('Unable to load XML');
}
return $doc;
}

public function fetchPageContents($url) {
$contents = file_get_contents($url);
if ($contents === FALSE) {
throw new Exception('Unable to load page contents');
}
return $contents;
}

public function getLinkFromEntry(SimpleXMLElement $entry) {
$url = $entry->link['href'];
return $url;
}

public function getImageUrl($contents, $regexPattern) {
$ret = preg_match($regexPattern, $contents, $matches);

if ($ret === FALSE) {
throw new Exception("Regex error occurred.");
} elseif ($ret === 0) {
throw new Exception("Regex did not match subject.");
} elseif ($ret !== 1) {
throw new Exception("Unexpected regex return value: $ret");
} elseif (count($matches) < 2) {
throw new Exception("Regex had no matches.");
}

$imageUrl = $matches[1];

return $imageUrl;
}
}
76 changes: 76 additions & 0 deletions classes/GenericComicService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
<?php

class GenericComicService {
protected $feed;
protected $feedService;
protected $log;
protected $pattern;
protected $entrySearchText;
protected $name;
protected $store;

public function __construct(
$name, FeedService $feedService,
Logger $logger, StorageService $store) {

$this->feedService = $feedService;
$this->log = $logger;
$this->name = $name;
$this->store = $store;
}

public function fetchAndStore() {
$xml = $this->fetch();
$filename = "feed_" . $this->name;
$this->store->save($filename, $xml);
}

protected function fetch() {
$doc = $this->feedService->fetchFeed($this->feed);

$count = count($doc->entry);
if ($count < 1) {
throw new Exception("No entries found in feed {$this->feed}.");
}

for ($i = $count - 1; $i >= 0; $i--) {
$entry = $doc->entry[$i];
if (strpos($entry->title, $this->entrySearchText) === FALSE) {
unset($doc->entry[$i]);
}
else {
$this->log->log("Processing $entry->title...");

if (isset($entry->description)) {
$entry->description = '';
} else {
$entry->addChild("description");
}

if (isset($entry->content)) {
unset($entry->content);
}

$newContents = $this->getEntryContents($entry);
$domNode = dom_import_simplexml($entry->description);
$owner = $domNode->ownerDocument;
$domNode->appendChild($owner->createCDATASection($newContents));
$this->log->log("\tDone.\n");
}
}
print_r($doc);
return $doc->asXml();
}

private function getEntryContents(SimpleXMLElement $entry) {
$url = $entry->link['href'];
$this->log->log("\tFetching URL: $url");
$contents = $this->feedService->fetchPageContents($url);

$imageUrl = $this->feedService->getImageUrl($contents, $this->pattern);

$newContents = "<img src=\"$imageUrl\"/>";

return $newContents;
}
}
7 changes: 7 additions & 0 deletions classes/Logger.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<?php

class Logger {
public function log($text) {
echo $text . "\n";
}
}
24 changes: 24 additions & 0 deletions classes/StorageService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?php

class StorageService {
private $prefix;
private $ctx;

public function __construct() {
$this->prefix = "gs://#default#/";
$options = ['gs' => ['Content-Type' => 'text/plain']];
$this->ctx = stream_context_create($options);
}

public function save($filename, $contents) {
file_put_contents($this->prefix . $filename, $contents, 0, $this->ctx);
}

public function load($filename) {
$newFilename = $this->prefix . $filename;
if (!file_exists($newFilename)) {
throw new Exception("Sorry. That feed does not exist.");
}
return file_get_contents($newFilename);
}
}
32 changes: 32 additions & 0 deletions classes/ViewService.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<?php

class ViewService {
protected $log;
protected $store;

public function __construct(Logger $logger, StorageService $store) {
$this->log = $logger;
$this->store = $store;
}

public function getFeed($requestUri) {
$pattern = "@^/view/(.+?)/(.+?)$@";
$ret = preg_match($pattern, $requestUri, $matches);

if ($ret === FALSE) {
throw new Exception("Regex error occurred.");
} elseif ($ret === 0) {
throw new Exception("Regex did not match subject.");
} elseif ($ret !== 1) {
throw new Exception("Unexpected regex return value: $ret");
} elseif (count($matches) < 3) {
throw new Exception("Regex had no matches.");
}

$feedName = $matches[1];
$feedType = $matches[2];
$filename = "feed_{$feedName}_{$feedType}";

return $this->store->load($filename);
}
}
5 changes: 5 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"require": {
"pimple/pimple": "~3.0"
}
}
64 changes: 64 additions & 0 deletions composer.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion php.ini
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
google_app_engine.enable_functions = "libxml_disable_entity_loader"
output_buffering = "Off"
output_buffering = "On"
18 changes: 18 additions & 0 deletions scripts/common.php
Original file line number Diff line number Diff line change
@@ -1,3 +1,21 @@
<?php

ob_start();
libxml_disable_entity_loader(false);

spl_autoload_register(function ($class) {
include __DIR__ . '/../classes/' . $class . '.php';
});

require(__DIR__ . '/../vendor/autoload.php');

require('scripts/dependency_injection.php');

set_exception_handler(function($ex) {
ob_end_clean();

header('Content-Type: text/plain');
http_response_code(500);

echo $ex->getMessage();
});
20 changes: 20 additions & 0 deletions scripts/dependency_injection.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

use Pimple\Container;

$container = new Container();
$container['logger'] = function($c) {
return new Logger;
};
$container['storage'] = function($c) {
return new StorageService;
};
$container['feed'] = function($c) {
return new FeedService($c['logger']);
};
$container['dilbert'] = function($c) {
return new DilbertService($c['feed'], $c['logger'], $c['storage']);
};
$container['view'] = function ($c) {
return new ViewService($c['logger'], $c['storage']);
};
8 changes: 8 additions & 0 deletions scripts/fetch_dilbert.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,14 @@
header("Content-Type: text/plain");
require_once("common.php");

$dilbert = $container['dilbert'];
$dilbert->fetchAndStore();

/*
$feed = "http://dilbert.com/feed.rss";
$pattern = '/data-image="(.+?)"/';
$doc = simplexml_load_file($feed) or die('Unable to load XML');
$count = count($doc->entry);
Expand Down Expand Up @@ -51,3 +58,4 @@ function get_image_url($contents) {
print_r($outputXml);
file_put_contents("gs://#default#/feed_dilbert_default", $outputXml);
*/
7 changes: 5 additions & 2 deletions scripts/view.php
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
<?php

require_once("common.php");

header("Content-Type: application/rss+xml");
echo file_get_contents("gs://#default#/feed_dilbert_default");
header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (60*60*2)) . ' GMT');
header('Cache-Control: public, must-revalidate, max-age=7200');

$view = $container['view'];
echo $view->getFeed($_SERVER['REQUEST_URI']);

0 comments on commit 66640d8

Please sign in to comment.