Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

359 lines
8.5KB

  1. <?php
  2. namespace App\Kintone;
  3. use App\Exceptions\ConfigException;
  4. use App\Kintone\Models\KintoneModel;
  5. use Exception;
  6. use Illuminate\Http\Client\Response;
  7. use Illuminate\Support\Collection;
  8. use Illuminate\Support\Facades\Http;
  9. use Log;
  10. /**
  11. * @template TValue of KintoneModel
  12. */
  13. class KintoneAccess
  14. {
  15. private string $appName;
  16. private string $host;
  17. private string $apiToken;
  18. private int $appId;
  19. private const DEFAULT_FIELDS = [
  20. "作成日時",
  21. "更新日時",
  22. '$id',
  23. '$revision',
  24. ];
  25. private array $fields = [];
  26. private string|null $cursor = null;
  27. private int $cursorDataCount = 0;
  28. private bool $hasNext = false;
  29. private const URL_RECORD = "/k/v1/record.json";
  30. private const URL_CURSOL = "/k/v1/records/cursor.json";
  31. private const URL_FILE = "/k/v1/file.json";
  32. public function __construct(string $appName)
  33. {
  34. $this->appName = $appName;
  35. $key = "kintone.host";
  36. $host = config($key);
  37. if (!$host) {
  38. throw new ConfigException("kintone.host", $host);
  39. }
  40. $key = "kintone.applications." . $appName . ".apiToken";
  41. $apiToken = config($key);
  42. if (!$apiToken) {
  43. throw new ConfigException($key, $apiToken);
  44. }
  45. $key = "kintone.applications." . $appName . ".appId";
  46. $appId = config($key);
  47. if (!$appId) {
  48. throw new ConfigException($key, $appId);
  49. }
  50. $this->host = $host;
  51. $this->apiToken = $apiToken;
  52. $this->appId = $appId;
  53. }
  54. public function setFields(array $fields): static
  55. {
  56. $this->fields = [
  57. ...$fields,
  58. ...self::DEFAULT_FIELDS,
  59. ];
  60. return $this;
  61. }
  62. public function __destruct()
  63. {
  64. $this->deleteCursor();
  65. }
  66. /**
  67. * @param integer $id
  68. * @return TValue
  69. */
  70. public function find(int $id)
  71. {
  72. $response = Http::withHeaders([
  73. "X-Cybozu-API-Token" => $this->apiToken,
  74. ])->get($this->getRecordUrl(), [
  75. "app" => $this->appId,
  76. "id" => $id,
  77. 'fields' => $this->fields,
  78. ]);
  79. if ($response->failed()) {
  80. $e = $response->toException();
  81. if ($e instanceof Exception) {
  82. Log::error($e->getMessage());
  83. throw $e;
  84. }
  85. }
  86. $result = new $this->appName();
  87. $result->setDataFromRecordResponse($response['record']);
  88. return $result;
  89. }
  90. /**
  91. * @param TValue $model
  92. * @return void
  93. */
  94. public function update(KintoneModel &$model)
  95. {
  96. $response = Http::withHeaders([
  97. "X-Cybozu-API-Token" => $this->apiToken,
  98. ])->put($this->getRecordUrl(), [
  99. "app" => $this->appId,
  100. "id" => $model->getRecordId(),
  101. "record" => $model->getApiLayout(),
  102. "revision" => $model->getRevision(),
  103. ]);
  104. if ($response->failed()) {
  105. $e = $response->toException();
  106. if ($e instanceof Exception) {
  107. Log::error($e->getMessage());
  108. throw $e;
  109. }
  110. }
  111. $model->clean($response["revision"]);
  112. return $response;
  113. }
  114. /**
  115. * @param TValue $model
  116. * @return void
  117. */
  118. public function create(KintoneModel &$model)
  119. {
  120. $response = Http::withHeaders([
  121. "X-Cybozu-API-Token" => $this->apiToken,
  122. ])->post($this->getRecordUrl(), [
  123. "app" => $this->appId,
  124. "record" => $model->getApiLayout(),
  125. ]);
  126. if ($response->failed()) {
  127. $e = $response->toException();
  128. if ($e instanceof Exception) {
  129. Log::error($e->getMessage());
  130. throw $e;
  131. }
  132. }
  133. $model->clean($response["revision"]);
  134. $model->setRecordId($response["id"]);
  135. return $response;
  136. }
  137. public function createCursor(KintoneRecordQuery|null $query = null)
  138. {
  139. $data = [
  140. "app" => $this->appId,
  141. 'fields' => $this->fields,
  142. ];
  143. if ($query !== null) {
  144. $data["query"] = $query->toQuery();
  145. }
  146. $response = Http::withHeaders([
  147. "X-Cybozu-API-Token" => $this->apiToken,
  148. ])->post($this->getCursorUrl(), $data);
  149. if ($response->failed()) {
  150. $e = $response->toException();
  151. if ($e instanceof Exception) {
  152. Log::error($e->getMessage(), ['data' => $data]);
  153. throw $e;
  154. }
  155. }
  156. $cursor = $response["id"];
  157. $totalCount = $response["totalCount"];
  158. if (0 < $totalCount) {
  159. $this->hasNext = true;
  160. $this->cursor = $cursor;
  161. $this->cursorDataCount = $totalCount;
  162. } else {
  163. $this->cursor = null;
  164. $this->hasNext = false;
  165. $this->cursorDataCount = 0;
  166. }
  167. return $response;
  168. }
  169. /**
  170. * @return Collection<int,TValue>
  171. */
  172. public function next()
  173. {
  174. if (!$this->hasNext) {
  175. return collect();
  176. }
  177. $response = Http::withHeaders([
  178. "X-Cybozu-API-Token" => $this->apiToken,
  179. ])->get($this->getCursorUrl(), [
  180. "id" => $this->cursor,
  181. ]);
  182. if ($response->failed()) {
  183. $e = $response->toException();
  184. if ($e instanceof Exception) {
  185. Log::error($e->getMessage());
  186. throw $e;
  187. }
  188. }
  189. $ret = collect();
  190. $hasNext = $response["next"];
  191. if (!$hasNext) {
  192. $this->cursor = null;
  193. $this->hasNext = false;
  194. $this->cursorDataCount = 0;
  195. }
  196. foreach ($response["records"] as $data) {
  197. /**
  198. * @var KintoneModel $model
  199. */
  200. $model = new $this->appName();
  201. $model->setDataFromRecordResponse($data);
  202. $ret->push($model);
  203. }
  204. return $ret;
  205. }
  206. /**
  207. * @return Collection<int,TValue>
  208. */
  209. public function all(KintoneRecordQuery|null $query = null)
  210. {
  211. if ($this->cursor !== null) {
  212. $this->deleteCursor();
  213. }
  214. $this->createCursor($query);
  215. $list = collect();
  216. while (true) {
  217. $ret = $this->next();
  218. foreach ($ret as $ele) {
  219. $list->push($ele);
  220. }
  221. if ($this->cursor === null) {
  222. break;
  223. }
  224. }
  225. return $list;
  226. }
  227. public function deleteCursor()
  228. {
  229. if ($this->cursor === null) {
  230. return;
  231. }
  232. $response = Http::withHeaders([
  233. "X-Cybozu-API-Token" => $this->apiToken,
  234. ])->delete($this->getCursorUrl(), [
  235. "id" => $this->cursor,
  236. ]);
  237. if ($response->failed()) {
  238. $e = $response->toException();
  239. if ($e instanceof Exception) {
  240. Log::error($e->getMessage());
  241. throw $e;
  242. }
  243. }
  244. $this->cursor = null;
  245. $this->hasNext = false;
  246. $this->cursorDataCount = 0;
  247. }
  248. public function fileGet(string $fileKey)
  249. {
  250. $response = Http::withHeaders([
  251. "X-Cybozu-API-Token" => $this->apiToken,
  252. "Content-Type" => "application/json",
  253. ])->get($this->getCursorUrl(), [
  254. "fileKey" => $fileKey,
  255. ]);
  256. if ($response->failed()) {
  257. $e = $response->toException();
  258. if ($e instanceof Exception) {
  259. Log::error($e->getMessage());
  260. throw $e;
  261. }
  262. }
  263. return $response;
  264. }
  265. public function filePut($file): string
  266. {
  267. $response = Http::withHeaders([
  268. "X-Cybozu-API-Token" => $this->apiToken,
  269. "Content-Type" => "multipart/form-data",
  270. ])->post($this->getCursorUrl(), $file);
  271. if ($response->failed()) {
  272. $e = $response->toException();
  273. if ($e instanceof Exception) {
  274. Log::error($e->getMessage());
  275. throw $e;
  276. }
  277. }
  278. return $response[''];
  279. }
  280. private function getRecordUrl()
  281. {
  282. return $this->getUrl(self::URL_RECORD);
  283. }
  284. private function getCursorUrl()
  285. {
  286. return $this->getUrl(self::URL_CURSOL);
  287. }
  288. private function getFileUrl()
  289. {
  290. return $this->getUrl(self::URL_FILE);
  291. }
  292. private function getUrl(string $path)
  293. {
  294. return $this->host . $path;
  295. }
  296. }