|
- <?php
-
- namespace App\Kintone\Models;
-
- use App\Exceptions\ConfigException;
- use App\Files\TmpFile;
- use App\Kintone\File;
- use App\Kintone\KintoneAccess;
- use App\Kintone\KintoneAccessStore;
- use App\Kintone\KintoneRecordQuery;
- use App\Kintone\Models\SubTable\SubTableData;
- use App\Util\DateUtil;
- use Illuminate\Http\UploadedFile;
- use Illuminate\Support\Arr;
- use Illuminate\Support\Carbon;
- use Illuminate\Support\Collection;
- use Illuminate\Support\Str;
- use LogicException;
- use stdClass;
-
- abstract class KintoneModel
- {
- const CONFIG_KEY = "";
-
- const BASE_MODEL = null;
-
- static public function configKey(): string
- {
- if (!static::CONFIG_KEY) {
- throw new LogicException(sprintf("Kintone 設定キー 未設定:%s", static::class));
- }
- return static::CONFIG_KEY;
- }
-
- static public function setConfig(): array
- {
-
- $configStr = env(static::configKey());
- if (!$configStr) {
- throw new ConfigException(static::configKey(), $configStr);
- }
-
- $params = explode(",", $configStr);
- if (count($params) !== 2) {
- throw new ConfigException(static::configKey(), $configStr);
- }
-
- [$apiToken, $appId] = $params;
-
- return [static::class => [
- 'apiToken' => $apiToken,
- 'appId' => (int)$appId,
- ]];
- }
-
- /**
- * @return KintoneAccess<static>
- */
- static public function getAccess(): KintoneAccess
- {
- $target = static::BASE_MODEL ?? static::class;
-
- $store = KintoneAccessStore::instance();
- if ($store->has($target)) {
- return $store->get($target);
- }
-
- $access = new KintoneAccess($target, static::class);
- $access->setFields(array_keys(static::FIELDS));
-
- foreach (static::RELATIONS as $relation) {
- $access->addAppToken($relation);
- }
-
- $store->set($target, $access);
- return $access;
- }
-
- /**
- * @return KintoneRecordQuery<static>
- */
- static public function getQuery(): KintoneRecordQuery
- {
- $target = static::BASE_MODEL ?? static::class;
- return new KintoneRecordQuery($target);
- }
-
- /**
- * @return static
- */
- public static function find(int $recordId)
- {
- return static::getAccess()->find($recordId);
- }
- /**
- * @return static
- */
- public static function first(?KintoneRecordQuery $query = null)
- {
- return static::getAccess()->first($query);
- }
-
- public static function getDropDownOptions(string $fieldCode): array
- {
- $ret = [];
- $properties = static::getAccess()->getAppFormFields();
- $options = Arr::get($properties, sprintf("%s.options", $fieldCode));
- $ret = Arr::pluck(Arr::sort($options, function ($option) {
- return data_get($option, "index");
- }), "label");
- return $ret;
- }
-
- protected ?string $recordId = null;
-
- protected ?int $revision = null;
-
- protected ?Carbon $createdAt = null;
-
- protected ?Carbon $updatedAt = null;
-
- protected ?stdClass $dataOrigin = null;
- protected stdClass $data;
-
- const FIELD_RECORD_NO = "レコード番号";
-
- protected const FIELDS = [];
-
- protected const SUB_TABLES = [];
-
- protected const FIELD_NAMES = [];
-
- protected const RELATIONS = [];
-
- private array $changed = [];
-
- public function __construct()
- {
- $this->data = new stdClass();
-
- foreach (static::FIELDS as $fileCode => $type) {
- if ($type === FieldType::SUBTABLE) {
- $this->set($fileCode, collect());
- }
- }
- }
-
- public function __get($name)
- {
- $field = "FIELD_" . Str::of($name)->snake()->upper()->toString();
- $constantPath = sprintf("%s::%s", static::class, $field);
- if (defined($constantPath)) {
- return $this->get(constant($constantPath));
- } else {
- throw new LogicException(sprintf("未定義のメンバアクセス %s %s", static::class, $field));
- }
- }
- public function __set($name, $value)
- {
- $field = "FIELD_" . Str::of($name)->snake()->upper()->toString();
- $constantPath = sprintf("%s::%s", static::class, $field);
- if (defined($constantPath)) {
- return $this->set(constant($constantPath), $value);
- } else {
- throw new LogicException(sprintf("未定義のメンバアクセス %s %s", static::class, $field));
- }
- }
-
- public function set(string $fieldCode, $value)
- {
- $type = $this->getFieldType($fieldCode);
- if ($type) {
- $this->setData($fieldCode, $value);
- data_set($this->changed, $fieldCode, true);
- }
- return $this;
- }
-
- private function setData(string $path, $value)
- {
- data_set($this->data, $path, $value);
-
- return $this;
- }
-
- public function setDataFromRecordResponse(array $data): bool
- {
- $ret = true;
- foreach ($data as $fieldCode => $ele) {
- $type = data_get($ele, "type");
- $value = data_get($ele, "value");
- if ($type === "__ID__") {
- $this->recordId = $value;
- continue;
- }
- if ($type === "__REVISION__") {
- $this->revision = $value;
- continue;
- }
- if ($type === "CREATED_TIME") {
- $this->createdAt = DateUtil::parse($value);
- continue;
- }
- if ($type === "UPDATED_TIME") {
- $this->updatedAt = DateUtil::parse($value);
- continue;
- }
-
- data_set($this->data, $fieldCode, $this->readData($ele, $fieldCode));
- }
-
- if ($this->recordId === null) {
- throw new LogicException(sprintf("レコード番号取得失敗 :%s", static::class));
- }
-
- $ret = $this->setDataCustom($data);
- if ($ret) {
- $this->clean();
- }
- return $ret;
- }
-
- private function readData(array $data, string $fieldCode = "")
- {
- $type = data_get($data, "type");
- $value = data_get($data, "value");
- if ($type === null || $value === null) {
- return null;
- }
-
- $type = FieldType::tryFrom($type);
- if ($type !== null) {
- if (in_array($type, [FieldType::DATETIME, FieldType::DATE])) {
- if ($value) {
- return DateUtil::parse($value);
- } else {
- return null;
- }
- }
- if ($type === FieldType::NUMBER) {
- return intval($value);
- }
- if ($type === FieldType::FILE) {
- $ret = [];
- foreach ($value as $f) {
- $ret[] = new File($f);
- }
- return $ret;
- }
- if ($type === FieldType::SUBTABLE && $this->getFieldType($fieldCode)) {
- $ret = collect();
- foreach ($value as $v) {
- $rowRet = [];
- $rowArray = data_get($v, 'value');
- $isEmptyRow = true;
- foreach ($rowArray as $subFieldCode => $ele) {
- $rowRet[$subFieldCode] = $this->readData($ele);
- if (!!$rowRet[$subFieldCode]) {
- $isEmptyRow = false;
- }
- }
- if (!$isEmptyRow) {
- $ret->push($this->getSubTableData($fieldCode, $rowRet));
- }
- }
- return $ret;
- }
-
- return $value;
- }
-
- return null;
- }
-
- private function getSubTableData(string $fieldCode, array $data): SubTableData
- {
- $className = data_get(static::SUB_TABLES, $fieldCode, "");
- if (class_exists($className)) {
- return new $className($data);
- }
- throw new LogicException("キントーン設定不備");
- }
-
-
-
- /**
- * 変更前データを現在データで上書きする
- *
- * @return void
- */
- public function clean(?int $revision = null)
- {
- $this->dataOrigin = clone $this->data;
- if ($revision !== null) {
- $this->revision = $revision;
- }
- $this->changed = [];
- }
-
- public function getApiLayout(): array
- {
- $ret = [];
- foreach (static::FIELDS as $fieldCode => $type) {
-
- // 変更があった項目のみレイアウトへ出力する
- if (!Arr::has($this->changed, $fieldCode)) {
- continue;
- }
-
- $path = sprintf("%s.value", $fieldCode);
- data_set($ret, $path, $this->getApiLayoutValue($fieldCode));
- }
-
- return array_merge($ret, $this->getApiLayoutCustom());
- }
-
- private function getApiLayoutValue(string $fieldCode)
- {
-
- $ret = [];
- $data = $this->get($fieldCode);
-
- $type = $this->getFieldType($fieldCode);
-
- if ($type === FieldType::DATETIME) {
- $data = $this->getDate($fieldCode);
- if ($data) {
- return $data->toIso8601ZuluString();
- } else {
- return "";
- }
- }
- if ($type === FieldType::DATE) {
- $data = $this->getDate($fieldCode);
- if ($data) {
- return $data->toDateString();
- } else {
- return "";
- }
- }
-
- if ($data instanceof Collection) {
- $ret = [];
- foreach ($data as $ele) {
- if ($ele instanceof SubTableData) {
- $obj = [];
-
- $values = $ele->toArray();
- foreach ($values as $subFieldCode => $value) {
- $obj['value'][$subFieldCode]['value'] = $value;
- }
- $ret[] = $obj;
- }
- }
- return $ret;
- }
- return data_get($this->data, $fieldCode);
- }
-
- private function getFieldType(string $fieldCode): ?FieldType
- {
- return data_get(static::FIELDS, $fieldCode);
- }
-
- public function get(string $key)
- {
- return data_get($this->data, $key);
- }
-
- public function getStr(string $key): ?string
- {
- return $this->get($key);
- }
-
- public function getNumber(string $key): ?int
- {
- return $this->get($key);
- }
-
- public function getDate(string $key): ?Carbon
- {
- return $this->get($key);
- }
-
- public function getTable(string $key): ?array
- {
- return $this->get($key);
- }
-
- public function setRecordId(string $id): static
- {
- $this->recordId = $id;
- return $this;
- }
- public function getRecordId(): ?string
- {
- return $this->recordId;
- }
-
- public function getRevision(): ?int
- {
- return $this->revision;
- }
-
- public function getUpdatedAt(): ?Carbon
- {
- return $this->updatedAt;
- }
- public function getCreatedAt(): ?Carbon
- {
- return $this->createdAt;
- }
-
- /**
- * @param string $fieldCode
- * @param Collection<int, UploadedFile|TmpFile> $files
- * @param bool $override
- * @return static
- */
- public function setFiles(string $fieldCode, Collection $files, bool $override = true): static
- {
- if ($override) {
- $this->set($fieldCode, []);
- }
- foreach ($files as $file) {
- $this->addFile($fieldCode, $file);
- }
- return $this;
- }
-
- public function addFile(string $fieldCode, UploadedFile|TmpFile $file)
- {
- if ($file instanceof UploadedFile) {
- $name = sprintf("image_%d.%s", Str::uuid(), $file->extension());
- $contentType = $file->getClientMimeType();
- } else {
- $name = $file->getAppFileName();
- $contentType = $file->getMimeType();
- }
- $access = $this->getAccess();
-
- $field = $this->get($fieldCode);
-
- array_push($field, [
- 'fileKey' => $access->filePut($file),
- 'name' => $name,
- 'contentType' => $contentType,
- ]);
-
- $this->set($fieldCode, $field);
- return $this;
- }
-
- public function save()
- {
- if (count($this->changed) === 0) {
- return;
- }
-
- $access = static::getAccess();
- if ($this->recordId === null) {
- $access->create($this);
- } else {
- $access->update($this);
- }
- }
-
- public function toArray($column = ['*']): array
- {
- if ($this->recordId === null) {
- throw new LogicException("保存前モデルのシリアライズ検知");
- }
-
- $ret = [
- 'record_no' => $this->recordId,
- 'revision' => $this->revision,
- ];
-
- $columnAll = data_get($column, 0) === '*';
-
- /**
- * @var string $fieldCode
- */
- foreach ($this->data as $fieldCode => $value) {
-
- if (!$columnAll && !in_array($fieldCode, $column)) {
- continue;
- }
-
- $type = data_get(static::FIELDS, $fieldCode);
-
- $columnName = data_get(static::FIELD_NAMES, $fieldCode, null);
- if ($columnName === null) {
- continue;
- }
-
- if ($type === null) {
- $ret[$columnName] = $value;
- continue;
- }
-
- if ($type === FieldType::DATETIME) {
- if ($value instanceof Carbon) {
- $ret[$columnName] = $value->format('Y/m/d H:i');
- } else {
- $ret[$columnName] = $value;
- }
- continue;
- }
- if ($type === FieldType::DATE) {
- if ($value instanceof Carbon) {
- $ret[$columnName] = $value->format('Y/m/d');
- } else {
- $ret[$columnName] = $value;
- }
- continue;
- }
-
-
- $ret[$columnName] = $value;
- }
- $ret = array_merge($ret, $this->toArrayCustom());
-
- return $ret;
- }
-
- protected function toArrayCustom(): array
- {
- return [];
- }
-
-
- /**
- * オーバーライドを期待
- *
- * @param array $data
- * @return boolean
- */
- protected function setDataCustom(array $data): bool
- {
- return true;
- }
- /**
- * オーバーライドを期待
- *
- * @return array
- */
- protected function getApiLayoutCustom(): array
- {
- return [];
- }
- }
|