diff options
Diffstat (limited to 'src/App.php')
-rw-r--r-- | src/App.php | 350 |
1 files changed, 38 insertions, 312 deletions
diff --git a/src/App.php b/src/App.php index 92ceb4a..15be58b 100644 --- a/src/App.php +++ b/src/App.php @@ -2,6 +2,10 @@ namespace FlatFileForms; +use FlatFileForms\Controllers\EntriesController; +use FlatFileForms\Controllers\FieldsController; +use FlatFileForms\Controllers\SubmissionController; +use FlatFileForms\Controllers\ValidationController; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; use Yosymfony\Toml\Toml; @@ -33,104 +37,34 @@ class App // check api key $apiKey = $_GET['key'] ?? $_POST['key'] ?? null; if (empty($apiKey)) { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - throw new \Exception('API key missing'); + throw new HttpException('API key missing', Response::HTTP_BAD_REQUEST); } if (! in_array($apiKey, $config['api']['keys'])) { - $response->setStatusCode(Response::HTTP_UNAUTHORIZED); - throw new \Exception('API key does not match'); + throw new HttpException('API key does not match', Response::HTTP_UNAUTHORIZED); } // GET if ($method == 'GET') { if (str_ends_with($path, '/fields')) { - $this->formPath = $formPath = $contentRoot . str_replace('/fields', '', $path); + $formPath = $contentRoot . str_replace('/fields', '', $path); - $fields = $this->buildFields($formPath, $_GET['page'] ?? null); + $builder = new Builder($formPath); - // flatten paged form - if ($this->isPagedFieldSet($fields) && isset($_GET['flat'])) { - $fields = array_merge(...array_values($fields)); - } + $fieldsController = new FieldsController(); - $content['data'] = $fields; + $content = $fieldsController->getFields($builder); } else if (str_ends_with($path, '/entries')) { if (! isset($_GET['dateFrom'])) { - $response->setStatusCode(Response::HTTP_BAD_REQUEST); - throw new \Exception('dateFrom parameter missing'); + throw new HttpException('dateFrom parameter missing', Response::HTTP_BAD_REQUEST); } - $this->formPath = $formPath = $contentRoot . str_replace('/entries', '', $path); - - $entries = []; - - $dateFrom = new \DateTime($_GET['dateFrom']); - $dateTo = new \DateTime($_GET['dateTo'] ?? 'now'); - - $dateRangeYears = range($dateFrom->format('Y'), $dateTo->format('Y')); - $dateRangeYearsCount = count($dateRangeYears); - foreach ($dateRangeYears as $dateRangeYearIdx => $dateRangeYear) { - $yearPath = "$formPath/entries/$dateRangeYear"; - if (! is_dir($yearPath)) { - continue; - } - - if ($dateRangeYearsCount === 1) { - $dateRangeMonths = range($dateFrom->format('m'), $dateTo->format('m')); - } - else if ($dateRangeYearIdx === 0) { - $dateRangeMonths = range($dateFrom->format('m'), 12); - } - else if ($dateRangeYearIdx === $dateRangeYearsCount - 1) { - $dateRangeMonths = range(1, $dateTo->format('m')); - } - else { - $dateRangeMonths = range(1, 12); - } - - $dateRangeMonthsCount = count($dateRangeMonths); - foreach ($dateRangeMonths as $dateRangeMonthIdx => $dateRangeMonth) { - $monthPath = "$yearPath/" . sprintf('%02d', $dateRangeMonth); - if (! is_dir($monthPath)) { - continue; - } - - if ($dateRangeMonthsCount === 1) { - $dateRangeDays = range($dateFrom->format('d'), $dateTo->format('d')); - } - else if ($dateRangeYearIdx === 0 && $dateRangeMonthIdx === 0) { - $dateRangeDays = range($dateFrom->format('d'), 31); - } - else if ($dateRangeYearIdx === $dateRangeYearsCount - 1 && $dateRangeMonthIdx === $dateRangeMonthsCount - 1) { - $dateRangeDays = range(1, $dateTo->format('d')); - } - else { - $dateRangeDays = range(1, 31); - } - - foreach ($dateRangeDays as $dateRangeDay) { - $dayPath = "$monthPath/" . sprintf('%02d', $dateRangeDay); - if (! is_dir($dayPath)) { - continue; - } - - $entriesForDay = $this->scandir($dayPath); - foreach ($entriesForDay as $entryForDay) { - $entry = Toml::parseFile("$dayPath/$entryForDay"); - if (isset($_GET['flat'])) { - $entries[] = $entry; - } else { - $entries[$dateRangeYear][$dateRangeMonth][$dateRangeDay][] = $entry; - } - } - } - - } - } + $formPath = $contentRoot . str_replace('/entries', '', $path); + + $entriesController = new EntriesController(); - $content['data'] = $entries; + $content = $entriesController->getEntries(); } else { @@ -141,46 +75,36 @@ class App // POST else if ($method == 'POST') { if (str_ends_with($path, '/validate')) { - $this->formPath = $formPath = $contentRoot . str_replace('/validate', '', $path); + $formPath = $contentRoot . str_replace('/validate', '', $path); - $fields = $this->buildFields($formPath, $_GET['page'] ?? null); + $builder = new Builder($formPath); + $validator = new Validator($formPath); - $content = $this->validateRequest($fields); + $validationController = new ValidationController(); + + $content = $validationController->validateRequest($builder, $validator); } else if (str_ends_with($path, '/submit')) { - $this->formPath = $formPath = $contentRoot . str_replace('/submit', '', $path); - - $fields = $this->buildFields($formPath); - - $content = $this->validateRequest($fields); - - // if there were no validation errors then add entry - if (empty($content['error'])) { - $date = new \Datetime(); - $entry = [ - 'fields' => $_POST, - 'date' => $date->format('c'), - ]; - - $builder = new TomlBuilder(); - $builder->addValue('date', $entry['date']); - $builder->addTable('fields'); - foreach ($entry['fields'] as $entryKey => $entryValue) { - $builder->addValue($entryKey, $entryValue); - } - - $entryDirectory = $formPath . '/entries/' . $date->format('Y/m/d'); - @mkdir($entryDirectory, 0774, true); - $entryFilename = $date->format('Ymd_Hi_') . hash('adler32', serialize($entry)) . '.toml'; - file_put_contents( - $entryDirectory . '/' . $entryFilename, - $builder->getTomlString() - ); + $formPath = $contentRoot . str_replace('/submit', '', $path); + + $builder = new Builder($formPath); + $validator = new Validator($formPath); + + $submissionController = new SubmissionController(); + + $content = $submissionController->submit($builder, $validator, $formPath); + + if (! empty($content['error'])) { + throw new HttpException($content['error'], Response::HTTP_UNPROCESSABLE_ENTITY); } } } } catch (\Exception $exception) { + if ($exception instanceof HttpException) { + $response->setStatusCode($exception->getCode()); + } + $content['error'] = basename(get_class($exception)) . ': ' . $exception->getMessage(); } @@ -190,178 +114,10 @@ class App $response->send(); } - /** - * @param array $fields - */ - public function validateRequest($fields) { - $content = []; - $hasInvalidFields = false; - - $fields = $this->validateFields($fields); - - if ($this->isPagedFieldSet($fields)) { - // remove surplus field values from response - $fields = array_map(function ($page) { - return array_map(function ($field) { - return array_intersect_key($field, array_flip([ - 'is_valid', - ])); - }, $page); - }, $fields); - - $flattened = array_merge(...array_values($fields)); - $hasInvalidFields = in_array(false, array_column($flattened, 'is_valid')); - } else { - // remove surplus field values from response - $fields = array_map(function ($field) { - return array_intersect_key($field, array_flip([ - 'is_valid', - ])); - }, $fields); - - $hasInvalidFields = in_array(false, array_column($fields, 'is_valid')); - } - - $content['data'] = $fields; - - if ($hasInvalidFields) { - $content['error'] = 'Invalid fields'; - } - - return $content; - } - - /** - * @param string $formPath - * @param mixed $page - */ - public function buildFields($formPath, $page = null) - { - $parsed = Toml::parseFile($formPath . '/fields/_fields.toml'); - $fields = []; - - // if a page is requested - if ($page) { - if (! isset($parsed['page'])) { - throw new \Exception('Form has no pages'); - } - - if (! isset($parsed['page'][$page])) { - throw new \Exception('Form has no page ' . $page); - } - - $fields = $this->buildSinglePageFields($parsed['page'][$page], $formPath); - } - - // else get all fields - else { - // if form is paged - if (isset($parsed['page'])) { - $pages = $parsed['page']; - foreach ($pages as $pageKey => $pageFields) { - $fields[$pageKey] = $this->buildSinglePageFields($pageFields, $formPath); - } - } - - // if form is not paged - else { - foreach ($parsed['field'] as $key => $field) { - $fields[$key] = $this->buildSingleField($formPath, $key, $field); - } - } - } - - return $fields; - } - - /** - * @param array $pageFields - * @param string $formPath - */ - public function buildSinglePageFields($pageFields, $formPath) - { - $fields = []; - - if (! empty($pageFields['file'])) { - $pageFields = array_replace_recursive($pageFields, Toml::parseFile($formPath . '/fields/' . $pageFields['file'])); - } - - foreach ($pageFields['field'] as $key => $field) { - $fields[$key] = $this->buildSingleField($formPath, $key, $field); - } - - return $fields; - } - - /** - * @param string $formPath - * @param string $key - * @param string $field - */ - public function buildSingleField($formPath, $key, $field) - { - if (! empty($field['file'])) { - $field = array_replace_recursive($field, Toml::parseFile($formPath . '/fields/' . $field['file'])); - } - - if (empty($field['name'])) { - $field['name'] = $key; - } - - return $field; - } - - /** - * @param array $fields - */ - public function validateFields($fields) - { - if ($this->isPagedFieldSet($fields)) { - foreach ($fields as $pageKey => &$pageFields) { - foreach ($pageFields as $key => &$field) { - $field = $this->validateSingleField($field); - } - } - } else { - foreach ($fields as $key => &$field) { - $field = $this->validateSingleField($field); - } - } - - return $fields; - } - - /** - * @param array $field - */ - public function validateSingleField($field) - { - $value = $_POST[$field['name']] ?? ''; - $field['is_valid'] = true; - - if (isset($field['required']) && empty($value)) { - $field['is_valid'] = false; - } - - if (isset($field['validation']['pattern']) && preg_match_all('/' . $field['validation']['pattern'] . '/', $value) === 0) { - $field['is_valid'] = false; - } - - $validationFunctionName = 'validate_' . basename($this->formPath) . '_' . $field['name']; - if (function_exists($validationFunctionName)) { - $field = call_user_func($validationFunctionName, $field, $value); - } - - return $field; - } - - /** - * @param string $formPath - */ - public function buildConfig($formPath) + public function buildConfig(string $requestPath): array { $config = []; - $currentDirectory = $formPath; + $currentDirectory = $requestPath; while (true) { $configFile = $currentDirectory . '/config/config.toml'; if (file_exists($configFile)) { @@ -387,34 +143,4 @@ class App return $config; } - - /** - * @param array $fields - */ - public function isPagedFieldSet($fields) - { - $firstItem = reset($fields); - - return ! (isset($firstItem['name']) && ! is_array($firstItem['name'])); - } - - /** - * @param string|array $paths - */ - public function scandir($paths) - { - $paths = (array)$paths; - - $scanned = []; - foreach ($paths as $path) { - $filtered = array_values( - array_filter( - scandir($path), fn ($item) => ! in_array($item, ['.', '..']) - ) - ); - array_push($scanned, ...$filtered); - } - - return $scanned; - } } |