sfneal /
laravel-helpers
| 1 | <?php |
||
| 2 | |||
| 3 | namespace Sfneal\Helpers\Laravel\Support; |
||
| 4 | |||
| 5 | use ErrorException; |
||
| 6 | use Illuminate\Support\Facades\Cache; |
||
| 7 | |||
| 8 | class Changelog |
||
| 9 | { |
||
| 10 | // todo: add ability to replace package names (user/package) with github links |
||
| 11 | |||
| 12 | /** |
||
| 13 | * @var string |
||
| 14 | */ |
||
| 15 | private $path; |
||
| 16 | |||
| 17 | /** |
||
| 18 | * Changelog constructor. |
||
| 19 | * |
||
| 20 | * @param string|null $path |
||
| 21 | */ |
||
| 22 | public function __construct(string $path = null) |
||
| 23 | { |
||
| 24 | $this->path = $path ?? config('app-info.changelog_path'); |
||
| 25 | } |
||
| 26 | |||
| 27 | /** |
||
| 28 | * Read the application's changelog & return an array of changes. |
||
| 29 | * |
||
| 30 | * @return array |
||
| 31 | */ |
||
| 32 | public function changelog(): array |
||
| 33 | { |
||
| 34 | return Cache::rememberForever((new CacheKey("changelog:$this->path", 'changelog'))->execute(), function () { |
||
| 35 | // Read the changelog |
||
| 36 | $file_lines = file($this->path); |
||
| 37 | $changes = []; |
||
| 38 | |||
| 39 | for ($row = 0; $row < count($file_lines); $row++) { |
||
|
0 ignored issues
–
show
|
|||
| 40 | // Check if line starts with 'version' |
||
| 41 | if (substr(strtolower($file_lines[$row]), 0, strlen('version')) == 'version') { |
||
| 42 | $version_date = explode(', ', $file_lines[$row]); |
||
| 43 | |||
| 44 | // Extract version and date |
||
| 45 | $date = $version_date[1]; |
||
| 46 | $version = explode(' ', $version_date[0])[1]; |
||
| 47 | $changes[$version] = ['date' => trim($date), 'changes' => []]; |
||
| 48 | |||
| 49 | // Skip ahead two lines to skip sep line |
||
| 50 | $row += 2; |
||
| 51 | |||
| 52 | // Keep iterating over rows until we get to a blank line |
||
| 53 | while ($row < count($file_lines) && strlen(trim($file_lines[$row])) > 1) { |
||
| 54 | if (substr(trim($file_lines[$row]), 0, 1) == '-') { |
||
| 55 | $changes[$version]['changes'][] = str_replace('- ', '', trim($file_lines[$row])); |
||
| 56 | $row++; |
||
| 57 | } else { |
||
| 58 | break; |
||
| 59 | } |
||
| 60 | } |
||
| 61 | } |
||
| 62 | } |
||
| 63 | |||
| 64 | return $changes; |
||
| 65 | }); |
||
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Retrieve an array of changes made to a particular application version. |
||
| 70 | * |
||
| 71 | * @param string|null $version |
||
| 72 | * @return array|null |
||
| 73 | */ |
||
| 74 | public function versionChanges(string $version): ?array |
||
| 75 | { |
||
| 76 | return Cache::rememberForever( |
||
| 77 | // Cache key |
||
| 78 | (new CacheKey("changelog:$this->path", $version))->execute(), |
||
| 79 | |||
| 80 | // Value to cache |
||
| 81 | function () use ($version) { |
||
| 82 | try { |
||
| 83 | return $this->changelog()[$version]; |
||
| 84 | } catch (ErrorException $exception) { |
||
| 85 | return null; |
||
| 86 | } |
||
| 87 | } |
||
| 88 | ); |
||
| 89 | } |
||
| 90 | |||
| 91 | /** |
||
| 92 | * Retrieve an array of the version history. |
||
| 93 | * |
||
| 94 | * - optionally include the release date in the array values |
||
| 95 | * |
||
| 96 | * @param bool $releaseDates |
||
| 97 | * @return array |
||
| 98 | */ |
||
| 99 | public function versions(bool $releaseDates = false): array |
||
| 100 | { |
||
| 101 | // Flat array of versions |
||
| 102 | $versions = array_keys($this->changelog()); |
||
| 103 | |||
| 104 | // Return an array of version keys & release date values |
||
| 105 | if ($releaseDates) { |
||
| 106 | // todo: optimize this |
||
| 107 | return array_combine( |
||
| 108 | $versions, |
||
| 109 | array_map( |
||
| 110 | function ($array) { |
||
| 111 | return $array['date']; |
||
| 112 | }, |
||
| 113 | array_values($this->changelog()) |
||
| 114 | ) |
||
| 115 | ); |
||
| 116 | } |
||
| 117 | |||
| 118 | // Return a array of versions |
||
| 119 | else { |
||
| 120 | return $versions; |
||
| 121 | } |
||
| 122 | } |
||
| 123 | } |
||
| 124 |
If the size of the collection does not change during the iteration, it is generally a good practice to compute it beforehand, and not on each iteration: