Skip to content

Commit

Permalink
Merge pull request #737 from hydephp/integrate-publications-seeder
Browse files Browse the repository at this point in the history
Integrate publications seeder
  • Loading branch information
caendesilva authored Dec 22, 2022
2 parents 07b740a + d1b80b7 commit 5c315dc
Show file tree
Hide file tree
Showing 6 changed files with 628 additions and 4 deletions.
107 changes: 107 additions & 0 deletions packages/framework/src/Console/Commands/SeedPublicationCommand.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
<?php

declare(strict_types=1);

namespace Hyde\Console\Commands;

use Hyde\Console\Concerns\ValidatingCommand;
use Hyde\Framework\Actions\SeedsPublicationFiles;
use Hyde\Framework\Features\Publications\Models\PublicationType;
use Hyde\Framework\Features\Publications\PublicationService;
use InvalidArgumentException;
use LaravelZero\Framework\Commands\Command;
use Rgasch\Collection\Collection;

/**
* Hyde Command to seed publication files for a publication type.
*
* @see \Hyde\Framework\Actions\SeedsPublicationFiles
* @see \Hyde\Framework\Testing\Feature\Commands\SeedPublicationCommandTest
*
* @todo Normalize command output style, maybe by hooking into the build actions?
*/
class SeedPublicationCommand extends ValidatingCommand
{
/** @var string */
protected $signature = 'seed:publications
{publicationType? : The name of the publication type to create publications for}
{number? : The number of publications to generate}';

/** @var string */
protected $description = 'Generate random publications for a publication type';

public function safeHandle(): int
{
$this->title('Seeding new publications!');

$pubType = $this->getPubTypeSelection($this->getPublicationTypes());
$number = (int) ($this->argument('number') ?? $this->askWithValidation(
'number',
'How many publications would you like to generate',
['required', 'integer', 'between:1,100000'], 1));

if ($number >= 10000) {
$this->warn('Warning: Generating a large number of publications may take a while. <fg=gray>Expected time: '.($number / 1000).' seconds.</>');
if (! $this->confirm('Are you sure you want to continue?')) {
return parent::USER_EXIT;
}
}

$timeStart = microtime(true);
$seeder = new SeedsPublicationFiles($pubType, $number);
$seeder->create();

$ms = round((microtime(true) - $timeStart) * 1000);
$each = round($ms / $number, 2);
$this->info(sprintf("<comment>$number</comment> publication{$this->pluralize($number)} for <comment>$pubType->name</comment> created! <fg=gray>Took {$ms}ms%s",
($number > 1) ? " ({$each}ms/each)</>" : ''));

return Command::SUCCESS;
}

/**
* @param \Rgasch\Collection\Collection<string, \Hyde\Framework\Features\Publications\Models\PublicationType> $pubTypes
* @return \Hyde\Framework\Features\Publications\Models\PublicationType
*/
protected function getPubTypeSelection(Collection $pubTypes): PublicationType
{
$pubTypeSelection = $this->argument('publicationType') ?? $pubTypes->keys()->get(
(int) $this->choice(
'Which publication type would you like to seed?',
$pubTypes->keys()->toArray()
)
);

if ($pubTypes->has($pubTypeSelection)) {
if ($this->argument('number')) {
$this->line("<info>Creating</info> [<comment>{$this->argument('number')}</comment>] <info>random publications for type</info> [<comment>$pubTypeSelection</comment>]");
} else {
$this->line("<info>Creating random publications for type</info> [<comment>$pubTypeSelection</comment>]");
}

return $pubTypes->get($pubTypeSelection);
}

throw new InvalidArgumentException("Unable to locate publication type [$pubTypeSelection]");
}

/**
* @return \Rgasch\Collection\Collection<string, PublicationType>
*
* @throws \InvalidArgumentException
*/
protected function getPublicationTypes(): Collection
{
$pubTypes = PublicationService::getPublicationTypes();
if ($pubTypes->isEmpty()) {
throw new InvalidArgumentException('Unable to locate any publication types. Did you create any?');
}

return $pubTypes;
}

protected function pluralize(int $count): string
{
return ($count === 1) ? '' : 's';
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ public function register(): void
Commands\DebugCommand::class,

Commands\ValidatePublicationsCommand::class,
Commands\SeedPublicationCommand::class,
]
);
}
Expand Down
209 changes: 209 additions & 0 deletions packages/framework/src/Framework/Actions/SeedsPublicationFiles.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
<?php

declare(strict_types=1);

namespace Hyde\Framework\Actions;

use Hyde\Framework\Actions\Concerns\CreateAction;
use Hyde\Framework\Actions\Contracts\CreateActionContract;
use Hyde\Framework\Features\Publications\Models\PublicationField;
use Hyde\Framework\Features\Publications\Models\PublicationType;
use Hyde\Framework\Features\Publications\PublicationService;
use Hyde\Pages\PublicationPage;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;
use function in_array;
use function rand;
use function substr;
use function time;
use function trim;
use function ucfirst;

/**
* Seed publication files for a publication type.
*
* @see \Hyde\Console\Commands\SeedPublicationCommand
* @see \Hyde\Framework\Testing\Feature\Actions\SeedsPublicationFilesTest
*/
class SeedsPublicationFiles extends CreateAction implements CreateActionContract
{
protected PublicationType $pubType;
protected int $number = 1;

protected array $matter;
protected string $canonicalValue;

public function __construct(PublicationType $pubType, int $number = 1)
{
$this->number = $number;
$this->pubType = $pubType;
}

protected function handleCreate(): void
{
$this->create();
}

public function create(): void
{
for ($i = 0; $i < $this->number; $i++) {
$this->matter = [];
$this->canonicalValue = '';

$this->generatePublicationData();
$identifier = Str::slug(substr($this->canonicalValue, 0, 64));

$page = new PublicationPage($identifier, $this->matter, '## Write something awesome.', $this->pubType);
$page->save();
}
}

protected function generatePublicationData(): void
{
$this->matter['__createdAt'] = Carbon::today()->subDays(rand(1, 360))->addSeconds(rand(0, 86400));
foreach ($this->pubType->getFields() as $field) {
$this->matter[$field->name] = $this->generateFieldData($field);
$this->getCanonicalFieldName($field);
}

if (! $this->canonicalValue) {
$this->canonicalValue = $this->fakeSentence(3);
}
}

protected function getDateTimeValue(): string
{
return date('Y-m-d H:i:s', rand(
time() - 86400 + (rand(0, 86400)),
time() - (86400 * 365) + (rand(0, 86400))
));
}

protected function getTextValue($lines): string
{
$value = '';

for ($i = 0; $i < $lines; $i++) {
$value .= $this->fakeSentence(rand(5, 20))."\n";
}

return $value;
}

protected function generateFieldData(PublicationField $field): string|int|float|array|bool
{
return match ($field->type->value) {
'array' => $this->getArrayItems(),
'boolean' => rand(0, 100) < 50,
'datetime' => $this->getDateTimeValue(),
'float' => rand(-10000000, 10000000) / 100,
'image' => 'https://picsum.photos/id/'.rand(1, 1000).'/400/400',
'integer' => rand(-100000, 100000),
'string' => substr($this->fakeSentence(10), 0, rand(0, 255)),
'tag' => $this->getTags($field),
'text' => $this->getTextValue(rand(3, 20)),
'url' => $this->fakeUrl(),
};
}

protected function getCanonicalFieldName(PublicationField $field): void
{
if ($this->canFieldTypeCanBeCanonical($field->type->value)) {
if ($field->name === $this->pubType->canonicalField) {
$this->canonicalValue = $this->matter[$field->name];
}
}
}

protected function canFieldTypeCanBeCanonical(string $value): bool
{
return in_array($value, ['url', 'text', 'string', 'integer', 'float', 'datetime', 'array']);
}

protected function getArrayItems(): array
{
$arrayItems = [];
for ($i = 0; $i < rand(3, 20); $i++) {
$arrayItems[] = $this->fakeWord();
}

return $arrayItems;
}

protected function getTags(PublicationField $field): string
{
$tags = PublicationService::getValuesForTagName($field->tagGroup, false);

return $tags->isEmpty() ? '' : $tags->random();
}

private const WORDS = [
'lorem', 'ipsum', 'dolor', 'sit',
'amet', 'consectetur', 'adipiscing', 'elit',
'a', 'ac', 'accumsan', 'ad',
'aenean', 'aliquam', 'aliquet', 'ante',
'aptent', 'arcu', 'at', 'auctor',
'augue', 'bibendum', 'blandit', 'class',
'commodo', 'condimentum', 'congue', 'consequat',
'conubia', 'convallis', 'cras', 'cubilia',
'cum', 'curabitur', 'curae', 'cursus',
'dapibus', 'diam', 'dictum', 'dictumst',
'dignissim', 'dis', 'donec', 'dui',
'duis', 'egestas', 'eget', 'eleifend',
'elementum', 'enim', 'erat', 'eros',
'est', 'et', 'etiam', 'eu',
'euismod', 'facilisi', 'facilisis', 'fames',
'faucibus', 'felis', 'fermentum', 'feugiat',
'fringilla', 'fusce', 'gravida', 'habitant',
'habitasse', 'hac', 'hendrerit', 'himenaeos',
'iaculis', 'id', 'imperdiet', 'in',
'inceptos', 'integer', 'interdum', 'justo',
'lacinia', 'lacus', 'laoreet', 'lectus',
'leo', 'libero', 'ligula', 'litora',
'lobortis', 'luctus', 'maecenas', 'magna',
'magnis', 'malesuada', 'massa', 'mattis',
'mauris', 'metus', 'mi', 'molestie',
'mollis', 'montes', 'morbi', 'mus',
'nam', 'nascetur', 'natoque', 'nec',
'neque', 'netus', 'nibh', 'nisi',
'nisl', 'non', 'nostra', 'nulla',
'nullam', 'nunc', 'odio', 'orci',
'ornare', 'parturient', 'pellentesque', 'penatibus',
'per', 'pharetra', 'phasellus', 'placerat',
'platea', 'porta', 'porttitor', 'posuere',
'potenti', 'praesent', 'pretium', 'primis',
'proin', 'pulvinar', 'purus', 'quam',
'quis', 'quisque', 'rhoncus', 'ridiculus',
'risus', 'rutrum', 'sagittis', 'sapien',
'scelerisque', 'sed', 'sem', 'semper',
'senectus', 'sociis', 'sociosqu', 'sodales',
'sollicitudin', 'suscipit', 'suspendisse', 'taciti',
'tellus', 'tempor', 'tempus', 'tincidunt',
'torquent', 'tortor', 'tristique', 'turpis',
'ullamcorper', 'ultrices', 'ultricies', 'urna',
'ut', 'varius', 'vehicula', 'vel',
'velit', 'venenatis', 'vestibulum', 'vitae',
'vivamus', 'viverra', 'volutpat', 'vulputate',
];

private function fakeSentence(int $words): string
{
$sentence = '';
for ($i = 0; $i < $words; $i++) {
$sentence .= $this->fakeWord().' ';
}

return ucfirst(trim($sentence)).'.';
}

private function fakeWord(): string
{
return Arr::random(self::WORDS);
}

private function fakeUrl(): string
{
return 'https://example.com/'.$this->fakeWord();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -58,33 +58,40 @@ public static function getMediaForPubType(PublicationType $pubType): Collection
/**
* Get all available tags.
*
* @param bool $reload Reload the tags from the filesystem
* @return \Rgasch\Collection\Collection
*
* @throws \Safe\Exceptions\FilesystemException
* @throws \Safe\Exceptions\JsonException
*/
public static function getAllTags(): Collection
public static function getAllTags(bool $reload = true): Collection
{
$filename = Hyde::path('tags.json');
if (! file_exists($filename)) {
return Collection::create();
}

return Collection::create(json_decode(file_get_contents($filename), true))->sortKeys();
static $tags = null;
if (! $tags || $reload) {
$tags = Collection::create(json_decode(file_get_contents($filename), true))->sortKeys();
}

return $tags;
}

/**
* Get all values for a given tag name.
*
* @param string $tagName
* @param bool $reload Reload the tags from the filesystem
* @return \Rgasch\Collection\Collection
*
* @throws \Safe\Exceptions\FilesystemException
* @throws \Safe\Exceptions\JsonException
*/
public static function getValuesForTagName(string $tagName): Collection
public static function getValuesForTagName(string $tagName, bool $reload = true): Collection
{
$tags = static::getAllTags();
$tags = self::getAllTags($reload);
if (! $tags->get($tagName)) {
return Collection::create();
}
Expand Down
Loading

0 comments on commit 5c315dc

Please sign in to comment.