Skip to content

Commit c2f7eda

Browse files
author
Michael Deck
committed
Merge branch 'main' into add-eager-loading
2 parents 9f58f65 + 28df4c0 commit c2f7eda

File tree

4 files changed

+154
-44
lines changed

4 files changed

+154
-44
lines changed

src/Database/Eloquent/FMModel.php

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,6 @@ abstract class FMModel extends Model
1919

2020
use FMHasRelationships;
2121

22-
23-
/**
24-
* The text format to use when saving/retrieving Date fields from FileMaker
25-
* @var string
26-
*/
27-
protected $dateFormat = 'n/j/Y g:i:s A';
28-
2922
/**
3023
* Indicates if the model should be timestamped.
3124
*
@@ -428,14 +421,26 @@ public function getContainersToWrite(){
428421
return $containers;
429422
}
430423

431-
protected function isContainer($field){
432-
return
433-
is_a($field, File::class) ||
434-
is_a($field, UploadedFile::class) ||
435-
(
436-
is_array($field) &&
437-
sizeof($field) === 2
438-
);
424+
protected function isContainer($field)
425+
{
426+
427+
// if this is a file then we know it's a container
428+
if ($this->isFile($field)) {
429+
return true;
430+
}
431+
432+
// if it's an array, it could be a file => filename key-value pair.
433+
// it's a conainer if the first object in the array is a file
434+
if (is_array($field) && sizeof($field) === 2 && $this->isFile($field[0]) ){
435+
return true;
436+
}
437+
438+
return false;
439+
}
440+
441+
protected function isFile($object){
442+
return (is_a($object, File::class) ||
443+
is_a($object, UploadedFile::class));
439444
}
440445

441446
/**

src/Database/Query/FMBaseBuilder.php

Lines changed: 108 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use _PHPStan_59fb0a3b2\Symfony\Component\String\Exception\RuntimeException;
88
use BlueFeather\EloquentFileMaker\Exceptions\FileMakerDataApiException;
9+
use DateTimeInterface;
910
use Illuminate\Database\Query\Builder;
1011
use Illuminate\Http\File;
1112
use Illuminate\Http\UploadedFile;
@@ -118,7 +119,7 @@ class FMBaseBuilder extends Builder
118119
* @var string[]
119120
*/
120121
public $operators = [
121-
'=','==', '', '!', '<', '>', '<=', '', '>=', '', '~',
122+
'=', '==', '', '!', '<', '>', '<=', '', '>=', '', '~',
122123
];
123124

124125

@@ -128,7 +129,6 @@ class FMBaseBuilder extends Builder
128129
protected $whereIns = [];
129130

130131

131-
132132
/**
133133
* Add a basic where clause to the query.
134134
*
@@ -137,7 +137,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
137137
{
138138

139139
// This is an "orWhere" type query, so add a find request and then work from there
140-
if ($boolean === 'or'){
140+
if ($boolean === 'or') {
141141
$this->addFindRequest();
142142
}
143143
// If the column is an array, we will assume it is an array of key-value pairs
@@ -171,6 +171,7 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
171171

172172
$currentFind[$this->getMappedFieldName($column)] = $operator . $value;
173173

174+
// add the where clause KvP to the last item in the array of wheres
174175
$this->wheres[$count > 1 ? $count - 1 : 0] = $currentFind;
175176

176177
return $this;
@@ -179,22 +180,29 @@ public function where($column, $operator = null, $value = null, $boolean = 'and'
179180
/**
180181
* Delete records from the database.
181182
*
183+
* @param null $recordId
182184
* @return int
183185
* @throws FileMakerDataApiException
184186
*/
185-
public function delete($recordId = null)
187+
public function delete($id = null): int
186188
{
187189
// If an ID is passed to the method we will delete the record with this internal FileMaker record ID
188-
if (! is_null($recordId)) {
189-
$this->recordId($recordId);
190+
if (! is_null($id)) {
191+
$this->where($this->defaultKeyName(), '=', $id);
190192
}
191-
192193
$this->applyBeforeQueryCallbacks();
193194

195+
// Check if we have a record ID to delete or if this is a query for a bulk delete
196+
if ($this->getRecordId() === null){
197+
// There's no individual record ID to delete, so do a bulk delete
198+
return $this->bulkDeleteFromQuery();
199+
}
200+
201+
194202
try {
195203
$this->connection->deleteRecord($this);
196-
} catch (FileMakerDataApiException $e){
197-
if ($e->getCode() === 101){
204+
} catch (FileMakerDataApiException $e) {
205+
if ($e->getCode() === 101) {
198206
// no record was found to be deleted, return modified count of 0
199207
return 0;
200208
} else {
@@ -205,6 +213,64 @@ public function delete($recordId = null)
205213
return 1;
206214
}
207215

216+
/**
217+
* Do a bulk delete from a where query
218+
*
219+
* @return int
220+
* @throws FileMakerDataApiException
221+
*/
222+
protected function bulkDeleteFromQuery(): int
223+
{
224+
225+
$records = $this->get();
226+
$deleteCount = 0;
227+
foreach ($records as $record) {
228+
try {
229+
$recordId = $record['recordId'];
230+
$this->deleteByRecordId($recordId);
231+
// increment our delete counter if we didn't hit an exception
232+
$deleteCount++;
233+
} catch (FileMakerDataApiException $e) {
234+
if ($e->getCode() === 101) {
235+
// no record was found to be deleted
236+
// continue on to the next record to attempt to delete without incrementing $deleteCount
237+
} else {
238+
throw $e;
239+
}
240+
}
241+
}
242+
// Return the count of deleted records
243+
return $deleteCount;
244+
245+
}
246+
247+
/**
248+
* Delete a record using the internal FileMaker record ID
249+
*
250+
* @param $recordId
251+
* @return int
252+
* @throws FileMakerDataApiException
253+
*/
254+
public function deleteByRecordId($recordId): int
255+
{
256+
257+
$this->recordId = $recordId;
258+
259+
try {
260+
$this->connection->deleteRecord($this);
261+
} catch (FileMakerDataApiException $e) {
262+
if ($e->getCode() === 101) {
263+
// no record was found to be deleted, return modified count of 0
264+
return 0;
265+
} else {
266+
throw $e;
267+
}
268+
}
269+
// we deleted the record, return modified count of 1
270+
return 1;
271+
272+
}
273+
208274
/**
209275
* Returns the internal FileMaker record ID returned in a previous query, used for things like edits and deletes. This is not the primary key in your database.
210276
* @return mixed
@@ -280,7 +346,7 @@ public function script($name, $param = null): FMBaseBuilder
280346
$this->script = $name;
281347

282348
// set the script parameter if one was passed in
283-
if ($param){
349+
if ($param) {
284350
$this->scriptParam = $param;
285351
}
286352

@@ -298,7 +364,7 @@ public function scriptPresort($name, $param = null): FMBaseBuilder
298364
$this->scriptPresort = $name;
299365

300366
// set the script parameter if one was passed in
301-
if ($param){
367+
if ($param) {
302368
$this->scriptPresortParam = $param;
303369
}
304370

@@ -316,7 +382,7 @@ public function scriptPrerequest($name, $param = null): FMBaseBuilder
316382
$this->scriptPrerequest = $name;
317383

318384
// set the script parameter if one was passed in
319-
if ($param){
385+
if ($param) {
320386
$this->scriptPrerequestParam = $param;
321387
}
322388

@@ -356,7 +422,7 @@ public function get($columns = ['*'])
356422
$records = collect($response['response']['data']);
357423

358424
// filter to only requested columns
359-
if ($columns !== ['*']){
425+
if ($columns !== ['*']) {
360426
$records = $records->intersectByKeys(array_flip($columns));
361427
}
362428
return $records;
@@ -427,7 +493,7 @@ public function omit($boolean = true): FMBaseBuilder
427493

428494
$currentFind['omit'] = $boolean ? 'true' : 'false';
429495

430-
$this->wheres[$count -1] = $currentFind;
496+
$this->wheres[$count - 1] = $currentFind;
431497

432498
return $this;
433499
}
@@ -522,7 +588,8 @@ public function editRecord()
522588
* @return bool
523589
* @throws FileMakerDataApiException
524590
*/
525-
public function createRecord(){
591+
public function createRecord()
592+
{
526593
$response = $this->connection->createRecord($this);
527594
return $response;
528595
}
@@ -598,7 +665,7 @@ public function duplicate(int $recordId): array
598665
/**
599666
* Update records in the database.
600667
*
601-
* @param array $values
668+
* @param array $values
602669
* @return int
603670
*/
604671
public function update(array $values)
@@ -635,18 +702,17 @@ public function findByRecordId($recordId)
635702
*/
636703
public function whereNull($columns, $boolean = 'and', $not = false)
637704
{
638-
if ($not){
705+
if ($not) {
639706
// where NOT null
640707
$this->where($columns, null, '*', $boolean);
641-
} else{
708+
} else {
642709
// where null
643710
$this->where($columns, null, '=', $boolean);
644711
}
645712
return $this;
646713
}
647714

648715

649-
650716
protected function addFindRequest()
651717
{
652718
array_push($this->wheres, []);
@@ -707,7 +773,8 @@ public function performScript($script = null, $param = null)
707773
* @param null $script
708774
* @param null $param
709775
*/
710-
public function executeScript($script = null, $param = null){
776+
public function executeScript($script = null, $param = null)
777+
{
711778
if ($script) {
712779
$this->script = $script;
713780
}
@@ -724,9 +791,9 @@ public function executeScript($script = null, $param = null){
724791
/**
725792
* Prepare the value and operator for a where clause.
726793
*
727-
* @param string $value
728-
* @param string $operator
729-
* @param bool $useDefault
794+
* @param string $value
795+
* @param string $operator
796+
* @param bool $useDefault
730797
* @return array
731798
*
732799
* @throws \InvalidArgumentException
@@ -742,34 +809,46 @@ public function prepareValueAndOperator($value, $operator, $useDefault = false)
742809
return [$value, $operator];
743810
}
744811

745-
public function setGlobalFields(array $globals){
812+
public function setGlobalFields(array $globals)
813+
{
746814
$this->globalFields = $globals;
747815
return $this->connection->setGlobalFields($this);
748816
}
817+
749818
/**
750819
* Retrieve the "count" result of the query.
751820
*
752-
* @param string $columns
821+
* @param string $columns
753822
* @return int
754823
*/
755824
public function count($columns = '*')
756825
{
757826
$this->limit(1);
758827
try {
759828
$result = $this->connection->performFind($this);
760-
} catch (FileMakerDataApiException $e){
761-
if ($e->getCode() === 401){
829+
} catch (FileMakerDataApiException $e) {
830+
if ($e->getCode() === 401) {
762831
// no records found - this is ok
763832
// return 0
764833
return 0;
765834
}
766835

767836
// not a 401, so throw it
768-
throw $e;
837+
throw $e;
769838
}
770839

771840
$count = $result['response']['dataInfo']['foundCount'];
772-
return (int) $count;
841+
return (int)$count;
842+
}
843+
844+
public function whereDate($column, $operator, $value = null, $boolean = 'and')
845+
{
846+
847+
if ($operator instanceof DateTimeInterface) {
848+
$operator = $operator->format('n/j/Y');
849+
}
850+
851+
return $this->where($column, $operator, $value, $boolean);
773852
}
774853

775854
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?php
2+
3+
namespace BlueFeather\EloquentFileMaker\Database\Query\Grammars;
4+
5+
use Illuminate\Database\Query\Grammars\Grammar;
6+
7+
class FMGrammar extends Grammar
8+
{
9+
10+
/**
11+
* Get the format for database stored dates.
12+
*
13+
* @return string
14+
*/
15+
public function getDateFormat()
16+
{
17+
return 'n/j/Y g:i:s A';
18+
}
19+
20+
}

src/Services/FileMakerConnection.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
use BlueFeather\EloquentFileMaker\Database\Eloquent\FMEloquentBuilder;
88
use BlueFeather\EloquentFileMaker\Database\Query\FMBaseBuilder;
9+
use BlueFeather\EloquentFileMaker\Database\Query\Grammars\FMGrammar;
910
use BlueFeather\EloquentFileMaker\Exceptions\FileMakerDataApiException;
1011
use GuzzleHttp\Exception\ConnectException;
1112
use GuzzleHttp\Exception\RequestException;
@@ -631,4 +632,9 @@ protected function retryMiddleware()
631632
return 0;
632633
});
633634
}
635+
636+
protected function getDefaultQueryGrammar()
637+
{
638+
return new FMGrammar();
639+
}
634640
}

0 commit comments

Comments
 (0)