diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/Controller/FeedController.php | 47 | ||||
| -rw-r--r-- | src/Controller/RouteController.php | 170 | ||||
| -rw-r--r-- | src/Model/ApiService.php | 286 | ||||
| -rw-r--r-- | src/Model/CacheService.php | 10 | ||||
| -rw-r--r-- | src/View/BaseTemplate.php | 35 |
5 files changed, 0 insertions, 548 deletions
diff --git a/src/Controller/FeedController.php b/src/Controller/FeedController.php deleted file mode 100644 index 8bba37f..0000000 --- a/src/Controller/FeedController.php +++ /dev/null @@ -1,47 +0,0 @@ -<?php - -namespace HN\Controllers; - -class FeedController -{ - /** - * @var string - */ - private string $canonical_url; - /** - * @var string - */ - private string $description; - /** - * @var string - */ - private string $title; - /** - * @var string - */ - private string $content; - /** - * @var false|string - */ - private mixed $current_year; - - public function __construct(string $canonical_url, string $description, string $title, string $content) - { - $this->canonical_url = $canonical_url; - $this->description = $description; - $this->title = $title; - $this->content = $content; - $this->current_year = date("Y"); - } - - /** - * Request template to be presented to the user - * - * @access public - * @author Christian Cleberg <[email protected]> - */ - public function render(): void - { - include_once 'src/View/BaseTemplate.php'; - } -} diff --git a/src/Controller/RouteController.php b/src/Controller/RouteController.php deleted file mode 100644 index e3b2236..0000000 --- a/src/Controller/RouteController.php +++ /dev/null @@ -1,170 +0,0 @@ -<?php - -namespace HN\Controllers; - -require_once 'src/Controller/FeedController.php'; - -use function HN\Models\GetApiResults; -use function HN\Models\ParseItem; -use function HN\Models\ParseStories; -use function HN\Models\ParseUser; - -class RouteController -{ - /** - * @var string - */ - private string $request; - - public function __construct(string $request) - { - $this->request = $request; - } - - /** - * Route the user to the appropriate function, based on the URL - * - * @access public - * @return void No return type; send user to FeedController->render() or a 404 error - * @author Christian Cleberg <[email protected]> - */ - public function routeUser(): void - { - include_once 'src/Model/ApiService.php'; - $path = ltrim($this->request, '/'); - $elements = explode('/', $path); - - switch (array_shift($elements)) { - case '': - case 'top': - $feed = new FeedController( - $GLOBALS['full_domain'], - 'The top stories from Hacker News, proxied by hn.', - 'hn', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/topstories.json?limitToFirst=10&orderBy="$key"' - ), - 'Top' - ) - ); - - $feed->render(); - break; - - case 'best': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/Best/', - 'The best stories from Hacker News, proxied by hn.', - 'hn ~ best', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/beststories.json?limitToFirst=10&orderBy="$key"' - ), - 'Best' - ) - ); - - $feed->render(); - break; - - case 'new': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/new/', - 'The newest stories from Hacker News, proxied by hn.', - 'hn ~ new', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/newstories.json?limitToFirst=10&orderBy="$key"' - ), - 'New' - ) - ); - - $feed->render(); - break; - - case 'ask': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/ask/', - 'The top asks from Hacker News, proxied by hn.', - 'hn ~ ask', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/askstories.json?limitToFirst=10&orderBy="$key"' - ), - 'Ask' - ) - ); - - $feed->render(); - break; - - case 'show': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/show/', - 'The latest showcases from Hacker News, proxied by hn.', - 'hn ~ show', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/showstories.json?limitToFirst=10&orderBy="$key"' - ), - 'Show' - ) - ); - - $feed->render(); - break; - - case 'job': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/job/', - 'The latest jobs from Hacker News, proxied by hn.', - 'hn ~ jobs', - ParseStories( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/jobstories.json?limitToFirst=10&orderBy="$key"' - ), - 'Job' - ) - ); - - $feed->render(); - break; - - case 'user': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/user/' . $elements[0], - 'The Hacker News profile for ' . $elements[0] . ', proxied by hn.', - 'hn ~ ' . $elements[0], - ParseUser( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/user/' . $elements[0] . '.json' - ), - 'User: ' . $elements[0] - ) - ); - - $feed->render(); - break; - - case 'item': - $feed = new FeedController( - $GLOBALS['full_domain'] . '/item/' . $elements[0], - 'Hacker News story ' . $elements[0] . ', proxied by hn.', - 'hn ~ ' . $elements[0], - ParseItem( - GetApiResults( - 'https://hacker-news.firebaseio.com/v0/item/' . $elements[0] . '.json' - ) - ) - ); - - $feed->render(); - break; - - default: - header('HTTP/1.1 404 Not Found'); - } - } -}
\ No newline at end of file diff --git a/src/Model/ApiService.php b/src/Model/ApiService.php deleted file mode 100644 index dce65e5..0000000 --- a/src/Model/ApiService.php +++ /dev/null @@ -1,286 +0,0 @@ -<?php - -namespace HN\Models; - -/** - * Extract a set of stories from the Hacker News API - * - * @access public - * @param string $api_url The API endpoint to use for extraction - * @return mixed The API results formatted into an HTML section - * @author Christian Cleberg <[email protected]> - */ -function GetApiResults(string $api_url): mixed -{ - $response = file_get_contents($api_url); - return json_decode($response, true); -} - -/** - * Formats a given set of API results into an HTML section - * - * @access public - * @param mixed $api_results The decoded API results - * @param string $inline_title The <h1> title to use in the HTML - * @return string $html_output The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ParseStories(mixed $api_results, string $inline_title): string -{ - if ($api_results == "null") { - return '<p>ERROR: Stories not found. API returned `null`.</p>'; - } else { - $html_output = '<h1>' . $inline_title . '</h1>'; - for ($i = 0; $i < count($api_results); $i++) { - $story_api_results = GetApiResults('https://hacker-news.firebaseio.com/v0/item/' . $api_results[$i] . '.json'); - $html_output .= ConstructStory($story_api_results); - } - - return $html_output; - } -} - -/** - *Extract a user's profile from Hacker News API and format in HTML - * - * @access public - * @param mixed $api_results The decoded API results - * @param string $inline_title The <h1> title to use in the HTML - * @return string $html_output The formatted HTML result of stories from the API - * @author Christian Cleberg <[email protected]> - */ -function ParseUser(mixed $api_results, string $inline_title): string -{ - if ($api_results == "null") { - return '<p>ERROR: User not found.</p>'; - } else { - // TODO: Create function to format $about using the following guidelines - // : https://news.ycombinator.com/formatdoc - // : hint: nl2br() will solve the first formatting requirement - $about = $api_results['about']; - $karma = $api_results['karma']; - $created = date('Y-m-d h:m:s', $api_results['created']); - - $html_output = <<<EOT - <div class="user-details"> - <h1>$inline_title</h1> - <p>About: $about</p> - <p>Karma: $karma</p> - <p>Created: <time datetime="$created">$created</time></p> - <br> - <h2>Recently Submitted</h2> - </div> - EOT; - - $limit = (count($api_results['submitted']) > 10) ? 10 : count($api_results['submitted']); - if (count($api_results['submitted']) > 0) { - for ($i = 0; $i < $limit; $i++) { - $user_api_results = GetApiResults('https://hacker-news.firebaseio.com/v0/item/' . $api_results['submitted'][$i] . '.json'); - $html_output .= GetItem($user_api_results); - } - } else { - $html_output .= '<p>User has no submissions.</p>'; - } - - return $html_output; - } -} - - -/** - * Formats one specific item requested by the user - * - * @access public - * @param mixed $api_results The decoded API results - * @param string $inline_title The <h1> title to use in the HTML - * @return string $html_output The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ParseItem(mixed $api_results): string -{ - if ($api_results == "null") { - return '<p>ERROR: User not found.</p>'; - } else { - $html_output = ''; - - if (in_array($api_results['type'], array("job", "story", "poll", "pollopt"))) { - $html_output .= ConstructStoryDiscussion($api_results); - } else { - if (array_key_exists('parent', $api_results)) { - $parent_api_results = GetApiResults('https://hacker-news.firebaseio.com/v0/item/' . $api_results['parent'] . '.json'); - $html_output .= GetItem($parent_api_results); - $html_output .= '<hr>'; - } - - $html_output .= GetItem($api_results); - - if ($api_results['descendants'] != 0) { - $html_output .= '<hr>'; - $child_api_results = GetApiResults('https://hacker-news.firebaseio.com/v0/item/' . $api_results['kids'][0] . '.json'); - $html_output .= GetItem($child_api_results); - } - } - - return $html_output; - } -} - - -/** - * Formats one item from the API to HTML - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function GetItem(mixed $api_results): string -{ - $type = $api_results['type']; - - return match ($type) { - 'story', 'job' => ConstructStory($api_results), - 'comment' => ConstructComment($api_results), - 'poll' => ConstructPoll($api_results), - 'pollopt' => ConstructPollOpt($api_results), - default => '[ERROR] Item type not found: ' . $type, - }; -} - - -/** - * Creates a story HTML element - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ConstructStory(mixed $api_results): string -{ - $id = $api_results['id']; - $url = $api_results['url']; - $title = $api_results['title']; - $time = date('Y-m-d h:m:s', $api_results['time']); - $by = $api_results['by']; - $score = $api_results['score']; - if (array_key_exists('descendants', $api_results)) { - $descendants = $api_results['descendants']; - } else { - $descendants = 'No'; - } - - return <<<EOT - <div class="story"> - <a href="$url">$title</a> - <p> - <time datetime="$time">$time</time> - by <a href="/user/$by/">$by</a> - | $score points - | <a href="/item/$id">$descendants comments</a> - </p> - </div> - EOT; -} - -/** - * Creates a story discussion page with comments - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ConstructStoryDiscussion(mixed $api_results): string -{ - $id = $api_results['id']; - $url = $api_results['url']; - $title = $api_results['title']; - $time = date('Y-m-d h:m:s', $api_results['time']); - $by = $api_results['by']; - $score = $api_results['score']; - $descendants = $api_results['descendants']; - if (array_key_exists('text', $api_results)) { - $text = $api_results['text']; - } else { - $text = ''; - } - - $html_output = <<<EOT - <div class="story-discussion"> - <h1><a href="$url" target="_blank" rel="noopener">$title</a></h1> - <p> - <time datetime="$time">$time</time> - by <a href="/user/$by/">$by</a> - | $score points - | <a href="/item/$id">$descendants comments</a> - </p> - <p>$text</p> - </div> - EOT; - - // TODO: Add support for more than just top-level kids (i.e., recursive). - if ($api_results['descendants'] != 0) { - $html_output .= <<<EOT - <div class="story-discussion-comments"> - <h2>Comments</h2> - EOT; - for ($i = 0; $i < count($api_results['kids']); $i++) { - $child_api_results = GetApiResults('https://hacker-news.firebaseio.com/v0/item/' . $api_results['kids'][$i] . '.json'); - $html_output .= GetItem($child_api_results); - } - $html_output .= '</div>'; - } - - return $html_output; -} - -/** - * Creates a comment HTML element - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ConstructComment(mixed $api_results): string -{ - $time = date('Y-m-d h:m:s', $api_results['time']); - $text = $api_results['text']; - $by = $api_results['by']; - $parent = $api_results['parent']; - - return <<<EOT - <div class="comment"> - <p>$text</p> - <p><i>Submitted in response to: <a href="/item/$parent/">$parent</a></i></p> - <p><time datetime="$time">$time</time> by <a href="/user/$by/">$by</a></p> - </div> - EOT; -} - -/** - * Creates a poll HTML element - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ConstructPoll(mixed $api_results): string -{ - return 'TODO'; -} - -/** - * Creates a poll-option HTML element - * - * @access public - * @param mixed $api_results The decoded API results - * @return string The formatted HTML result of stories from the API or the error message - * @author Christian Cleberg <[email protected]> - */ -function ConstructPollOpt(mixed $api_results): string -{ - return 'TODO'; -} diff --git a/src/Model/CacheService.php b/src/Model/CacheService.php deleted file mode 100644 index ccb0db4..0000000 --- a/src/Model/CacheService.php +++ /dev/null @@ -1,10 +0,0 @@ -<?php - -/** - * TODO: Implement a way to cache certain content in SQLite or something similarly performative - * - * @access public - * @return void - * @author Christian Cleberg <[email protected]> - */ -function CacheService() {}
\ No newline at end of file diff --git a/src/View/BaseTemplate.php b/src/View/BaseTemplate.php deleted file mode 100644 index 1aa25ab..0000000 --- a/src/View/BaseTemplate.php +++ /dev/null @@ -1,35 +0,0 @@ -<!doctype html> -<html lang="en"> - -<head> - <title><?php echo $this->title; ?></title> - <meta charset="UTF-8"> - <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> - <meta http-equiv="x-ua-compatible" content="ie=edge"> - <meta name="author" content="<?php echo $GLOBALS['author_name']; ?>"> - <meta name="description" content="<?php echo $this->description; ?>"> - <link rel="canonical" href="<?php echo $this->canonical_url; ?>"> - <link rel="stylesheet" href="/static/styles.min.css"> -</head> - -<body> -<main id="main"> - <nav class="links"> - <span><a href="/">Top</a> · </span> - <span><a href="/best/">Best</a> ·</span> - <span><a href="/new/">New</a> ·</span> - <span><a href="/ask/">Ask</a> ·</span> - <span><a href="/show/">Show</a> ·</span> - <span><a href="/job/">Job</a></span> - </nav> - <?php echo $this->content; ?> -</main> - -<footer> - <p><a href="https://git.cleberg.net/hn.git">Source Code</a></p> - <p>Copyright © 2023 - <?php echo $this->current_year; ?></p> -</footer> - -</body> - -</html> |
