Skip to content

Commit cb92ea6

Browse files
committed
changed getpathname to getpath + filename for better compatibility
1 parent 073941e commit cb92ea6

File tree

2 files changed

+84
-9
lines changed

2 files changed

+84
-9
lines changed

src/Database/Query/FMBaseBuilder.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -734,7 +734,13 @@ public function whereBetween($column, iterable $values, $boolean = 'and', $not =
734734
}
735735

736736

737-
public function modId(int $modId)
737+
/**
738+
* Set the FileMaker record modId for editing an existing record.
739+
* FileMaker modIds look like numbers, but must always be strings.
740+
* @param string $modId
741+
* @return $this
742+
*/
743+
public function modId(string $modId)
738744
{
739745
$this->modId = $modId;
740746
return $this;

src/Services/FileMakerConnection.php

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@
1515
use Illuminate\Database\Connection;
1616
use Illuminate\Http\Client\PendingRequest;
1717
use Illuminate\Support\Arr;
18+
use Illuminate\Support\Collection;
1819
use Illuminate\Support\Facades\Cache;
20+
use Symfony\Component\HttpFoundation\File\File;
1921
use Illuminate\Support\Facades\Http;
2022
use Psr\Http\Message\RequestInterface;
2123
use Psr\Http\Message\ResponseInterface;
@@ -104,7 +106,7 @@ protected function getRecordUrl()
104106
protected function getLayoutUrl($layout = null)
105107
{
106108
// Set the connection layout as the layout parameter, otherwise get the layout from the connection
107-
if($layout){
109+
if ($layout) {
108110
$this->setLayout($layout);
109111
}
110112
return $this->getDatabaseUrl() . '/layouts/' . $this->getLayout();
@@ -155,17 +157,17 @@ public function uploadToContainerField(FMBaseBuilder $query)
155157
* The array should be in the format:
156158
* [ $file, 'myFile.pdf' ]
157159
*/
158-
if (is_array($query->containerFile)){
160+
if (is_array($query->containerFile)) {
159161
// we have a file and file name
160162
$file = $query->containerFile[0];
161163
$filename = $query->containerFile[1];
162-
} else{
164+
} else {
163165
$file = $query->containerFile;
164166
$filename = $file->getFilename();
165167
}
166168

167169
// create a stream resource
168-
$stream = fopen($file->getPath().'/'.$file->getFilename(), 'r');
170+
$stream = fopen($file->getPath() . '/' . $file->getFilename(), 'r');
169171

170172
$request = Http::attach('upload', $stream, $filename);
171173
$response = $this->makeRequest('post', $url, [], $request);
@@ -313,6 +315,7 @@ public function editRecord(FMBaseBuilder $query)
313315
return $response;
314316
}
315317

318+
316319
/**
317320
* Attempt to emulate a sql update in FileMaker
318321
*
@@ -331,7 +334,26 @@ public function update($query, $bindings = [])
331334
// This is just a single record to edit
332335
try {
333336
// Do the update
334-
$this->editRecord($query);
337+
338+
// Insert container data before updating text fields since scripts can be attached to the regular record edit
339+
340+
// Only attempt to write modified container fields
341+
// Figure out which fields are containers vs non-containers
342+
$textDataFields = $this->getNonContainerFieldsForRecordWrite($query->fieldData) ?? [];
343+
$modifiedContainerFields = collect($query->fieldData)->diffKeys($textDataFields);
344+
foreach ($modifiedContainerFields as $containerField => $fileData) {
345+
$eachResponse = $query->recordId($query->getRecordId())->setContainer($containerField, $fileData);
346+
$query->modId($this->getModIdFromFmResponse($eachResponse));
347+
}
348+
349+
// only do an edit record if there are non-container fields to edit
350+
// It's technically valid in the FileMaker Data API to call edit with no fields to modify to create a
351+
// record, but that doesn't really match Laravel's behavior. Users who want to do this should
352+
// call edit() directly.
353+
if ($textDataFields->count() > 0) {
354+
$this->editRecord($query);
355+
}
356+
335357
} catch (FileMakerDataApiException $e) {
336358
// Record is missing is ok for laravel functions
337359
// Throw if it isn't error code 101, which is missing record
@@ -346,6 +368,11 @@ public function update($query, $bindings = [])
346368
return 1;
347369
}
348370

371+
protected function getModIdFromFmResponse($response)
372+
{
373+
return $response['response']['modId'];
374+
}
375+
349376
/**
350377
* @param FMBaseBuilder $query
351378
* @return int
@@ -377,7 +404,7 @@ protected function performFindAndUpdateResults(FMBaseBuilder $query)
377404
$builder->layout($query->from);
378405
try {
379406
// Do the update
380-
$this->editRecord($builder);
407+
$this->update($builder);
381408
// Update if we don't get a record missing exception
382409
$updatedCount++;
383410
} catch (FileMakerDataApiException $e) {
@@ -422,7 +449,7 @@ protected function buildPostDataFromQuery(FMBaseBuilder $query)
422449
// only set field data if it exists
423450
if ($query->fieldData) {
424451
// fieldData needs to have a value if it's there, but an empty object is ok instead of null
425-
$postData['fieldData'] = $query->fieldData ?? json_decode("{}");
452+
$postData['fieldData'] = $this->getNonContainerFieldsForRecordWrite($query->fieldData) ?? json_decode("{}");
426453
}
427454

428455
// attribute => parameter
@@ -475,6 +502,47 @@ protected function buildPostDataFromQuery(FMBaseBuilder $query)
475502
return $postData;
476503
}
477504

505+
/**
506+
* Strip out containers and read-only fields to prepare for a write query
507+
* OR - do the opposite and get ONLY containers
508+
*
509+
* @return Collection
510+
*/
511+
protected function getNonContainerFieldsForRecordWrite($fieldArray)
512+
{
513+
514+
$fieldData = collect($fieldArray);
515+
516+
// Remove any fields which have been set to write a file, as they should be handled as containers
517+
foreach ($fieldData as $key => $field) {
518+
// remove any containers to be written.
519+
// users can set the field to be a File, UploadFile, or array [$file, 'MyFile.pdf']
520+
if ($this->isContainer($field)) {
521+
$fieldData->forget($key);
522+
}
523+
}
524+
return $fieldData;
525+
}
526+
527+
protected function isContainer($field)
528+
{
529+
530+
// if this is a file then we know it's a container
531+
if (is_a($field, File::class)) {
532+
return true;
533+
}
534+
535+
// if it's an array, it could be a file => filename key-value pair.
536+
// it's a conainer if the first object in the array is a file
537+
if (is_array($field) && sizeof($field) === 2 && $this->isFile($field[0])) {
538+
return true;
539+
}
540+
541+
return false;
542+
}
543+
544+
545+
478546
public function executeScript(FMBaseBuilder $query)
479547
{
480548
$this->setLayout($query->from);
@@ -643,7 +711,8 @@ protected function getDefaultQueryGrammar()
643711
return new FMGrammar();
644712
}
645713

646-
public function getLayoutMetadata($layout = null){
714+
public function getLayoutMetadata($layout = null)
715+
{
647716
$response = $this->makeRequest('get', $this->getLayoutUrl($layout));
648717
return $response['response'];
649718
}

0 commit comments

Comments
 (0)