Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.x] Add Form submissions query builder / facade #6455

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
8dd9081
Make Form submissions queryable and add facade
ryanmitchell Aug 5, 2022
6adc349
Remove extra line break
ryanmitchell Aug 5, 2022
879c9d0
Remove debug
ryanmitchell Aug 5, 2022
33f052b
Handle when $this->data() is a collection
ryanmitchell Aug 5, 2022
ce03447
Provide methods required by ExistsAsFile to Submission
ryanmitchell Aug 5, 2022
1cc4320
SubmissionStoreTest
ryanmitchell Aug 5, 2022
8bbe278
StyleCI
ryanmitchell Aug 5, 2022
dd98c50
Revert unintentional config change
ryanmitchell Aug 5, 2022
ecd91af
Update Submission class to use stache directory
ryanmitchell Aug 5, 2022
0ea42ca
SubmissionQueryBuilderTests
ryanmitchell Aug 5, 2022
653c510
Update TestCase to ensure tests run correctly
ryanmitchell Aug 5, 2022
1a9ef3f
StyleCI
ryanmitchell Aug 5, 2022
5249af0
StyleCI
ryanmitchell Aug 5, 2022
08afa94
Final tests
ryanmitchell Aug 5, 2022
cf42882
Revert test change as it was causing errors
ryanmitchell Aug 5, 2022
a5eb654
A bit more test jigging
ryanmitchell Aug 5, 2022
c4c161e
And some more
ryanmitchell Aug 5, 2022
4d224e4
Remove unnecessary orwheres
ryanmitchell Aug 6, 2022
0ea591e
Support for querying by date
ryanmitchell Aug 8, 2022
40a2b7f
StyleCI
ryanmitchell Aug 8, 2022
42acaea
Use FormSubmission facade to get and make submissions
ryanmitchell Jun 23, 2023
e98d600
Merge branch '4.x' into feature/submissions-query-builder
ryanmitchell Jun 23, 2023
053e9e4
Bug fixes
ryanmitchell Jun 23, 2023
716129d
Thank you Jason
ryanmitchell Jun 23, 2023
c8b7d10
Overload fileData on the Submission class rather than changing the trait
ryanmitchell Jun 23, 2023
6a1bdab
Also delete through the Facade
ryanmitchell Jun 23, 2023
b87bdfd
Defer to Submission respository for finding, allows it to be more eff…
ryanmitchell Jun 24, 2023
6fd9b83
Bind QueryBuilder to make it easier to override elsewhere
ryanmitchell Jun 24, 2023
acde848
Merge branch '4.x' into pr/6455
duncanmcclean Dec 6, 2023
7f143b6
Run Pint 🍺
duncanmcclean Dec 6, 2023
79ef397
Merge branch '4.x' into feature/submissions-query-builder
ryanmitchell Jan 11, 2024
62b81bb
fixes
ryanmitchell Jan 11, 2024
df3caec
:beer:
ryanmitchell Jan 11, 2024
5b001a9
Fix test failure
ryanmitchell Jan 11, 2024
4d8706c
Merge branch 'master' into pr/6455
duncanmcclean Apr 3, 2024
c0088ca
swap out string helpers
duncanmcclean Apr 3, 2024
d3b38ca
🍺
duncanmcclean Apr 3, 2024
190896f
plural like the rest
jasonvarga Apr 4, 2024
447c108
move assets back, one less diff
jasonvarga Apr 4, 2024
7f096a0
nitpick and update test
jasonvarga Apr 4, 2024
d6dadd0
copypasta
jasonvarga Apr 4, 2024
103620a
not needed
jasonvarga Apr 4, 2024
6589b88
fix var
jasonvarga Apr 4, 2024
6ce621c
keep date so it gets warmed
jasonvarga Apr 4, 2024
3e5c7b7
copy pasta
jasonvarga Apr 4, 2024
134442b
not needed
jasonvarga Apr 5, 2024
4b0c50a
prevent saving new files to disk
jasonvarga Apr 5, 2024
ac1ef0c
this either
jasonvarga Apr 5, 2024
7c81812
test creation
jasonvarga Apr 5, 2024
3ceadf7
not needed
jasonvarga Apr 5, 2024
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
5 changes: 5 additions & 0 deletions config/stache.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,11 @@
'directory' => base_path('users'),
],

'form-submissions' => [
'class' => Stores\SubmissionsStore::class,
'directory' => storage_path('forms'),
],

],

/*
Expand Down
8 changes: 8 additions & 0 deletions src/Contracts/Forms/SubmissionQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<?php

namespace Statamic\Contracts\Forms;

interface SubmissionQueryBuilder
{
//
}
22 changes: 22 additions & 0 deletions src/Contracts/Forms/SubmissionRepository.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<?php

namespace Statamic\Contracts\Forms;

interface SubmissionRepository
{
public function all();

public function whereForm(string $handle);

public function whereInForm(array $handles);

public function find($id);

public function make();

public function query();

public function save($entry);

public function delete($entry);
}
29 changes: 29 additions & 0 deletions src/Facades/FormSubmission.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?php

namespace Statamic\Facades;

use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Facade;
use Statamic\Contracts\Forms\Submission as SubmissionContract;
use Statamic\Contracts\Forms\SubmissionRepository;
use Statamic\Stache\Query\SubmissionQueryBuilder;

/**
* @method static Collection all()
* @method static Collection whereForm(string $handle)
* @method static Collection whereInForm(array $handles)
* @method static SubmissionContract find($id)
* @method static SubmissionContract make()
* @method static SubmissionQueryBuilder query()
* @method static save()
* @method static delete()
*
* @see \Statamic\Contracts\Forms\FormRepository
*/
class FormSubmission extends Facade
{
protected static function getFacadeAccessor()
{
return SubmissionRepository::class;
}
}
25 changes: 4 additions & 21 deletions src/Forms/Form.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
namespace Statamic\Forms;

use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Support\Facades\Log;
use Statamic\Contracts\Data\Augmentable;
use Statamic\Contracts\Data\Augmented;
use Statamic\Contracts\Forms\Form as FormContract;
Expand All @@ -18,15 +17,14 @@
use Statamic\Events\FormSaving;
use Statamic\Facades\Blueprint;
use Statamic\Facades\File;
use Statamic\Facades\Folder;
use Statamic\Facades\Form as FormFacade;
use Statamic\Facades\FormSubmission;
use Statamic\Facades\YAML;
use Statamic\Forms\Exceptions\BlueprintUndefinedException;
use Statamic\Forms\Exporters\Exporter;
use Statamic\Statamic;
use Statamic\Support\Arr;
use Statamic\Support\Traits\FluentlyGetsAndSets;
use Statamic\Yaml\ParseException;

class Form implements Arrayable, Augmentable, FormContract
{
Expand Down Expand Up @@ -295,20 +293,7 @@ public function metrics($metrics = null)
*/
public function submissions()
{
$path = config('statamic.forms.submissions').'/'.$this->handle();

return collect(Folder::getFilesByType($path, 'yaml'))->map(function ($file) {
try {
$data = YAML::parse(File::get($file));
} catch (ParseException $e) {
$data = [];
Log::warning('Could not parse form submission file: '.$file);
}

return $this->makeSubmission()
->id(pathinfo($file)['filename'])
->data($data);
});
return FormSubmission::whereForm($this->handle());
}

/**
Expand All @@ -319,9 +304,7 @@ public function submissions()
*/
public function submission($id)
{
return $this->submissions()->filter(function ($submission) use ($id) {
return $submission->id() === $id;
})->first();
return FormSubmission::find($id);
}

/**
Expand All @@ -331,7 +314,7 @@ public function submission($id)
*/
public function makeSubmission()
{
$submission = app(Submission::class);
$submission = FormSubmission::make();

$submission->form($this);

Expand Down
29 changes: 23 additions & 6 deletions src/Forms/Submission.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@
use Statamic\Contracts\Data\Augmentable;
use Statamic\Contracts\Forms\Submission as SubmissionContract;
use Statamic\Data\ContainsData;
use Statamic\Data\ExistsAsFile;
use Statamic\Data\HasAugmentedData;
use Statamic\Data\TracksQueriedColumns;
use Statamic\Data\TracksQueriedRelations;
use Statamic\Events\SubmissionCreated;
use Statamic\Events\SubmissionCreating;
use Statamic\Events\SubmissionDeleted;
use Statamic\Events\SubmissionSaved;
use Statamic\Events\SubmissionSaving;
use Statamic\Facades\Asset;
use Statamic\Facades\File;
use Statamic\Facades\YAML;
use Statamic\Facades\FormSubmission;
use Statamic\Facades\Stache;
use Statamic\Forms\Uploaders\AssetsUploader;
use Statamic\Forms\Uploaders\FilesUploader;
use Statamic\Support\Arr;
use Statamic\Support\Traits\FluentlyGetsAndSets;

class Submission implements Augmentable, SubmissionContract
{
use ContainsData, FluentlyGetsAndSets, HasAugmentedData;
use ContainsData, ExistsAsFile, FluentlyGetsAndSets, HasAugmentedData, TracksQueriedColumns, TracksQueriedRelations;

/**
* @var string
Expand Down Expand Up @@ -167,7 +170,7 @@ public function save()
}
}

File::put($this->getPath(), YAML::dump(Arr::removeNullValues($this->data()->all())));
FormSubmission::save($this);

foreach ($afterSaveCallbacks as $callback) {
$callback($this);
Expand All @@ -187,7 +190,7 @@ public function save()
*/
public function delete()
{
File::delete($this->getPath());
FormSubmission::delete($this);

SubmissionDeleted::dispatch($this);
}
Expand All @@ -199,7 +202,16 @@ public function delete()
*/
public function getPath()
{
return config('statamic.forms.submissions').'/'.$this->form()->handle().'/'.$this->id().'.yaml';
return $this->path();
}

public function path()
{
return vsprintf('%s/%s/%s.yaml', [
rtrim(Stache::store('form-submissions')->directory(), '/'),
$this->form()->handle(),
$this->id(),
]);
}

/**
Expand Down Expand Up @@ -237,6 +249,11 @@ public function blueprint()
return $this->form->blueprint();
}

public function fileData()
{
return $this->data()->all();
}

public function __get($key)
{
return $this->get($key);
Expand Down
2 changes: 2 additions & 0 deletions src/Providers/AppServiceProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ public function register()
\Statamic\Contracts\Structures\NavigationRepository::class => \Statamic\Stache\Repositories\NavigationRepository::class,
\Statamic\Contracts\Assets\AssetRepository::class => \Statamic\Assets\AssetRepository::class,
\Statamic\Contracts\Forms\FormRepository::class => \Statamic\Forms\FormRepository::class,
\Statamic\Contracts\Forms\SubmissionRepository::class => \Statamic\Stache\Repositories\SubmissionRepository::class,
])->each(function ($concrete, $abstract) {
if (! $this->app->bound($abstract)) {
Statamic::repository($abstract, $concrete);
Expand Down Expand Up @@ -155,6 +156,7 @@ public function register()

collect([
'entries' => fn () => Facades\Entry::query(),
'form-submissions' => fn () => Facades\FormSubmission::query(),
'terms' => fn () => Facades\Term::query(),
'assets' => fn () => Facades\Asset::query(),
'users' => fn () => Facades\User::query(),
Expand Down
125 changes: 125 additions & 0 deletions src/Stache/Query/SubmissionQueryBuilder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
<?php

namespace Statamic\Stache\Query;

use Illuminate\Support\Collection;
use Statamic\Contracts\Forms\SubmissionQueryBuilder as QueryBuilderContract;
use Statamic\Facades;

class SubmissionQueryBuilder extends Builder implements QueryBuilderContract
{
protected $forms;

public function where($column, $operator = null, $value = null, $boolean = 'and')
{
if ($column === 'form') {
$this->forms[] = $operator;

return $this;
}

return parent::where($column, $operator, $value, $boolean);
}

public function whereIn($column, $values, $boolean = 'and')
{
if (in_array($column, ['form', 'forms'])) {
$this->forms = array_merge($this->forms ?? [], $values);

return $this;
}

return parent::whereIn($column, $values, $boolean);
}

protected function collect($items = [])
{
return Collection::make($items);
}

protected function getFilteredKeys()
{
$forms = empty($this->forms)
? Facades\Form::all()->map->handle()
: $this->forms;

return empty($this->wheres)
? $this->getKeysFromForms($forms)
: $this->getKeysFromFormsWithWheres($forms, $this->wheres);
}

protected function getKeysFromForms($forms)
{
return collect($forms)->flatMap(function ($form) {
$keys = $this->store->store($form)->paths()->keys();

return collect($keys)->map(function ($key) use ($form) {
return "{$form}::{$key}";
});
});
}

protected function getKeysFromFormsWithWheres($forms, $wheres)
{
return collect($wheres)->reduce(function ($ids, $where) use ($forms) {
$keys = $where['type'] == 'Nested'
? $this->getKeysFromFormsWithWheres($forms, $where['query']->wheres)
: $this->getKeysFromFormsWithWhere($forms, $where);

return $this->intersectKeysFromWhereClause($ids, $keys, $where);
});
}

protected function getKeysFromFormsWithWhere($forms, $where)
{
$items = collect($forms)->flatMap(function ($form) use ($where) {
return $this->getWhereColumnKeysFromStore($form, $where);
});

$method = 'filterWhere'.$where['type'];

return $this->{$method}($items, $where)->keys();
}

protected function getOrderKeyValuesByIndex()
{
$forms = empty($this->forms)
? Facades\Form::all()->map->handle()
: $this->forms;

// First, we'll get the values from each index grouped by form
$keys = collect($forms)->map(function ($form) {
$store = $this->store->store($form);

return collect($this->orderBys)->mapWithKeys(function ($orderBy) use ($form, $store) {
$items = $store->index($orderBy->sort)
->items()
->mapWithKeys(function ($item, $key) use ($form) {
return ["{$form}::{$key}" => $item];
})->all();

return [$orderBy->sort => $items];
});
});

// Then, we'll merge all the corresponding index values together from each form.
return $keys->reduce(function ($carry, $form) {
foreach ($form as $sort => $values) {
$carry[$sort] = array_merge($carry[$sort] ?? [], $values);
}

return $carry;
}, collect());
}

protected function getWhereColumnKeyValuesByIndex($column)
{
$forms = empty($this->forms)
? Facades\Form::all()->map->handle()
: $this->forms;

return collect($forms)->flatMap(function ($form) use ($column) {
return $this->getWhereColumnKeysFromStore($form, ['column' => $column]);
});
}
}
Loading
Loading