Created
February 8, 2016 13:06
-
-
Save ryanmr/2ca51085a7b4655b86dd to your computer and use it in GitHub Desktop.
This file contains 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 | |
namespace App\Http\Controllers\Frontend; | |
use Illuminate\Http\Request; | |
use App\Http\Requests; | |
use App\Http\Controllers\Controller; | |
use \Carbon\Carbon; | |
use \App\Episode; | |
class FeedsController extends Controller | |
{ | |
public function feedMaster() { | |
$episodes = \App\Episode::visible()->recent()->get(); | |
return view('frontend.feeds.master', ['episodes' => $episodes]); | |
} | |
/** | |
* getFeedReplayQuery | |
* | |
* URL example: nexus.app/{series_slug}/feed/{fringe?}?begin=1453726381 | |
* | |
* Based on the existence of the ?begin query string, determine | |
* the interval of now and the ?begin DateTimes, and then add that to the first published_at. | |
* | |
* Flow: | |
* 1. Get the timestamp ?begin or bail early by returning the $query. | |
* 2. Convert it from a UNIX timestamp to Carbon | |
* 3. Get the published_at Carbon of the first episode in the series | |
* 4. Find the difference in days between that episode and ?begin | |
* 5. Calculate an ending date from the first episode's published at, plus the difference in days. | |
* 6. Return a query modification whereBetween, those dates. | |
*/ | |
private function getFeedReplayQuery(Request $request, $series_slug, $query) { | |
// find the ?query parameter `begin` | |
$timestamp = $request->input('begin', null); | |
// if it's null or not numeric, bail | |
// TODO: more cleaning is likely required here for $timestamp | |
if ($timestamp == null || !is_numeric($timestamp)) { | |
// this is malformed, maybe, and let's get out | |
return $query; | |
} | |
// when did this timestamp'd version of the feed begin? | |
$feedBegan = Carbon::createFromTimestamp($timestamp); | |
// try/catch here to prevent an episode-less series from | |
// throwing an unhandled exception firstOrFail does fail | |
try { | |
$firstEpisode = Episode::visible()->withSlug($series_slug)->firstOrFail(); | |
} catch (\Exception $e) { | |
return $query; | |
} | |
// in case there's a glitch, assume that published_at and created_at are effectively the same | |
$firstPublished = $firstEpisode->published_at != null ? $firstEpisode->published_at : $firstEpisode->created_at; | |
$now = Carbon::now(); | |
$days = $now->diffInDays($feedBegan); | |
// add the now-begin difference to $firstPublished | |
$untilPublished = $firstPublished->copy()->addDays($days); | |
return $query->whereBetween('published_at', [$firstPublished, $untilPublished]); | |
} | |
/** | |
* feedGeneral | |
* | |
* Get the series and feed in a single query, | |
* and if required by the ?begin query, fetch them from a | |
* limited range. | |
*/ | |
public function feedGeneral(Request $request, $series_slug) { | |
// this is a constraint closure that is applied to the | |
// episodes eager loading subquery; inside of this is a | |
// condition that triggers only if begin is present | |
$episodesConstraint = function($query) use ($request, $series_slug) { | |
$query->visible()->recent(); | |
if ($request->has('begin')) { | |
$this->getFeedReplayQuery($request, $series_slug, $query); | |
} | |
}; | |
$series = \App\Series::with(['episodes' => $episodesConstraint]) | |
->visible() | |
->whereSlug($series_slug) | |
->firstOrFail(); | |
return view('frontend.feeds.primary', ['series' => $series, 'episodes' => $series->episodes]); | |
} | |
/** | |
* feedFringe | |
* | |
* Handle the feed when there is a fringe to be included. | |
* | |
* TODO: optimize this, a lot. | |
*/ | |
public function feedFringe(Request $request, $series_slug) { | |
// get the series information | |
$series = \App\Series::visible() | |
->withSlug($series_slug) | |
->firstOrFail(); | |
// get all of the recent episodes | |
// related are loaded because they are queried next | |
$episodes = \App\Episode::with(['related']) | |
->visible() | |
->recent() | |
->withSlug($series_slug); | |
if ($request->has('begin')) { | |
$this->getFeedReplayQuery($request, $series_slug, $episodes); | |
} | |
$episodes = $episodes->get(); | |
// build a list of ids that need to be included | |
// the episode itself and the fringe of that episode | |
$included_ids = array(); | |
foreach ($episodes as $episode) { | |
$included_ids[] = $episode->id; | |
if ( $episode->related->count() > 0 ) { | |
foreach ($episode->related as $related) { | |
if ( $related->pivot->type == 'fringe' ) { | |
$included_ids[] = $related->id; | |
} | |
} | |
} | |
} | |
/** | |
* TODO: Ideally, the included_ids or the following query would be cached, | |
* and only cleared if something was saved. | |
*/ | |
/* | |
* TODO: | |
* Convert this multi-query version to the better unified SQL single query version. | |
*/ | |
$episodes = \App\Episode::with(['related', 'media', 'series']) | |
->visible() | |
->recent() | |
->whereIn('id', $included_ids) | |
->get(); | |
return view('frontend.feeds.primary', ['series' => $series, 'episodes' => $episodes]); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment