Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions DOCUMENTATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,31 @@ Reports will stick around until deleted, so you are free to compare reports to s

You may generate a report through the Control Panel, or by running `php please seo-pro:generate-report`.

### Storage

By default, reports are stored as YAML files in the `storage/statamic/seopro/reports` directory. You can change this in the config:

```php
// config/statamic/seo-pro.php

'reports' => [
'driver' => 'file',
'directory' => storage_path('statamic/seopro/reports'),
],
```

Where the filesystem is not shared between processes or does not survive a deploy (containers, serverless platforms, autoscaled instances), a report written by one process is never seen by the next request. In that case you may store reports in the database by changing the driver:

```php
// config/statamic/seo-pro.php

'reports' => [
'driver' => 'database',
],
```

Then run `php please seo-pro:database-reports` to publish the migration and import existing reports.

### Queuing Reports

Depending on the size of your site, generating a report may take a while. To prevent request timeouts, you may enable queues, and the reports will be truly queued in the background.
Expand Down
2 changes: 2 additions & 0 deletions config/seo-pro.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@
],

'reports' => [
'driver' => 'file',
'directory' => storage_path('statamic/seopro/reports'),
'keep_recent' => 'all',
'queue_chunk_size' => 1000,
'title_length' => [
Expand Down
103 changes: 103 additions & 0 deletions src/Commands/PublishReportMigrations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
<?php

namespace Statamic\SeoPro\Commands;

use Illuminate\Console\Command;
use Illuminate\Support\Facades\Artisan;
use Illuminate\Support\Facades\File;
use Statamic\Console\RunsInPlease;
use Statamic\SeoPro\Reporting\Eloquent\ReportRepository as EloquentReportRepository;
use Statamic\SeoPro\Reporting\File\ReportRepository as FileReportRepository;
use Statamic\SeoPro\Reporting\Report;
use Statamic\Support\Str;

use function Laravel\Prompts\confirm;
use function Laravel\Prompts\progress;

class PublishReportMigrations extends Command
{
use RunsInPlease;

protected $signature = 'statamic:seo-pro:database-reports';

protected $description = 'Publishes migration for the SEO Pro reports tables.';

public function handle()
{
$this
->publishMigration()
->runMigration()
->importReports();
}

private function publishMigration(): self
{
$name = 'create_seo_pro_reports_tables.php';

$existingMigration = collect(File::allFiles(database_path('migrations')))
->map->getFilename()
->filter(fn (string $filename) => Str::contains($filename, $name))
->first();

if ($existingMigration) {
$this->components->info("Migration [database/migrations/{$existingMigration}] already exists.");

return $this;
}

$filename = date('Y_m_d_His').'_'.$name;

$contents = File::get(__DIR__.'/stubs/'.$name);

File::put(database_path('migrations/'.$filename), $contents);

$this->components->info("Migration [database/migrations/{$filename}] published successfully.");

return $this;
}

private function runMigration(): self
{
Artisan::call('migrate', ['--force' => true], $this->output);

$this->newLine();

return $this;
}

private function importReports(): self
{
if (! confirm('Would you like to import existing reports?')) {
return $this;
}

$files = app(FileReportRepository::class);
$database = app(EloquentReportRepository::class);

$reports = $files->all();

if ($reports->isEmpty()) {
$this->components->info('There are no reports to import.');

return $this;
}

$progress = progress(label: 'Importing reports', steps: $reports->count());

$progress->start();

$reports->each(function (Report $report) use ($files, $database, $progress) {
$database->save($report);

$files->pages($report)->each(fn ($page) => $database->savePage($page));

$progress->advance();
});

$progress->finish();

$this->components->info('Reports imported successfully.');

return $this;
}
}
56 changes: 56 additions & 0 deletions src/Commands/stubs/create_seo_pro_reports_tables.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
/**
* Run the migrations.
*/
public function up(): void
{
Schema::create('seo_pro_reports', function (Blueprint $table) {
$table->id();
$table->dateTime('date');
$table->string('status');
$table->float('score')->nullable();
$table->integer('pages_crawled')->nullable();
$table->integer('pages_actionable')->nullable();
$table->json('results')->nullable();
$table->timestamps();
});

Schema::create('seo_pro_report_pages', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('report_id');
$table->string('page_id');
$table->json('data');
$table->json('results')->nullable();
$table->timestamps();

$table->unique(['report_id', 'page_id']);
});

Schema::create('seo_pro_report_chunks', function (Blueprint $table) {
$table->id();
$table->unsignedBigInteger('report_id');
$table->integer('chunk_id');
$table->json('content_ids');
$table->timestamps();

$table->index('report_id');
});
}

/**
* Reverse the migrations.
*/
public function down(): void
{
Schema::dropIfExists('seo_pro_report_chunks');
Schema::dropIfExists('seo_pro_report_pages');
Schema::dropIfExists('seo_pro_reports');
}
};
28 changes: 17 additions & 11 deletions src/Reporting/Chunk.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

use Illuminate\Support\Facades\Cache;
use Statamic\Facades\Data;
use Statamic\Facades\File;
use Statamic\Facades\YAML;
use Statamic\SeoPro\Cascade;
use Statamic\SeoPro\GetsSectionDefaults;
use Statamic\SeoPro\SiteDefaults\SiteDefaults;
Expand All @@ -25,21 +23,24 @@ public function __construct($id, $contentIds, Report $report)
$this->report = $report;
}

protected function folderPath()
public function id()
{
return $this->report->chunksFolder()."/{$this->id}";
return $this->id;
}

protected function yamlPath()
public function contentIds()
{
return $this->folderPath().'/chunk.yaml';
return $this->contentIds;
}

public function report()
{
return $this->report;
}

public function save()
{
File::put($this->yamlPath(), YAML::dump([
'ids' => $this->contentIds,
]));
$this->repository()->saveChunk($this);

return $this;
}
Expand All @@ -61,7 +62,7 @@ protected function generate($ids)
$this->createPage($content[$id] ?? Data::find($id))?->save();
}

File::delete($this->folderPath());
$this->repository()->deleteChunk($this);

if ($this->wasLastChunk()) {
$this->report->finalize();
Expand All @@ -70,7 +71,12 @@ protected function generate($ids)

protected function wasLastChunk()
{
return File::getFolders($this->report->chunksFolder())->isEmpty();
return ! $this->repository()->hasChunks($this->report);
}

protected function repository()
{
return app(ReportRepository::class);
}

protected function createPage($content)
Expand Down
19 changes: 19 additions & 0 deletions src/Reporting/Eloquent/ReportChunkModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?php

namespace Statamic\SeoPro\Reporting\Eloquent;

use Illuminate\Database\Eloquent\Model;

class ReportChunkModel extends Model
{
protected $table = 'seo_pro_report_chunks';

protected $guarded = [];

public function casts(): array
{
return [
'content_ids' => 'json',
];
}
}
23 changes: 23 additions & 0 deletions src/Reporting/Eloquent/ReportModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Statamic\SeoPro\Reporting\Eloquent;

use Illuminate\Database\Eloquent\Model;

class ReportModel extends Model
{
protected $table = 'seo_pro_reports';

protected $guarded = [];

public function casts(): array
{
return [
'date' => 'datetime',
'score' => 'float',
'pages_crawled' => 'integer',
'pages_actionable' => 'integer',
'results' => 'json',
];
}
}
20 changes: 20 additions & 0 deletions src/Reporting/Eloquent/ReportPageModel.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Statamic\SeoPro\Reporting\Eloquent;

use Illuminate\Database\Eloquent\Model;

class ReportPageModel extends Model
{
protected $table = 'seo_pro_report_pages';

protected $guarded = [];

public function casts(): array
{
return [
'data' => 'json',
'results' => 'json',
];
}
}
Loading
Loading