У меня странная проблема с чтением кодированных json данных, возвращаемых моим CakePHP3 API в ответ на вызов ajax из jQuery. Я уже прочитал более 20 сообщений о stackoverflow и в других местах и о обычных проблемах, с которыми сталкивались люди, когда из-за неправильного dataType, contentType или сервер не получал данные из ajax. Ни один из этих случаев здесь не применим (я пробовал разные настройки, не влияющие на мою проблему).
Проблема:
Мой ajax вызов отправляет некоторые параметры В моем API CakePHP3 API правильно получает параметры и возвращает закодированный json массив сущностей Cake PHP (каждая сущность имеет дополнительное свойство 'available_yield', добавленное перед отправкой обратно в вызов ajax). Я получаю правильный вывод, используя прямой URL в браузере (проверил его с помощью json валидаторов, все хорошо), но мой вызов ajax (я использовал вкладки консоли и сети в Chrome devtools для исследования) показывает пустой массив для правильно сформированного json.
Мое исследование показало, что проблема возникает, когда я изменяю сущности Cake PHP. Если я верну исходные данные из закодированного API json, jquery ajax получит правильные данные. Но когда я изменяю любую сущность, массив в jquery ajax пуст.
Отладка из Cake PHP показывает, что оба массива (неизмененные и измененные) выглядят одинаково, за исключением добавленного свойства, т.е. они корректны и во всех отношениях ОК, оба в json, оба в браузере в порядке. Но измененный вариант не принимается jquery как json.
На данный момент решение выглядит следующим образом: не изменяйте свои данные! Но это то, что мы делаем на сервере перед отправкой соответствующих и обработанных данных клиенту, не так ли?
У кого-нибудь была подобная проблема?
Я прилагаю свой код:
Торт PHP Функция API:
function myFunction(){
$params = $this->getRequest()->getQueryParams();
//debug($params);
$componentReference = $params['component_reference'];
$componentTypeId = $params['component_type_id'];
$matchingCrops = $this->Crops->find()->select(['id', 'grower_name', 'bulk'])->where(['reference' => $componentReference]);
$cropsWithYieldInfo = []; //to hold modify crop
foreach($matchingCrops as $crop){
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$crop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $crop;
}
}
// debug($cropsWithYieldInfo);
// debug($matchingCrops);
//$content = json_encode($cropsWithYieldInfo); // <<-- changing to $matchingCrops makes ajax see the array, but the array does not have my calculated data
$content = json_encode($matchingCrops);
$this->response = $this->response->withStringBody($content);
$this->response = $this->response->withType('json');
$this->autoRender = false;
return $this->response;
}
my AJAX:
function myAjax(){
$.ajax({
type: 'GET',
url: url,
//contentType: "application/json",
dataType: "json"
})
.done(function (data) {
console.log(data);
})
.fail(function (data) {
console.log('AJAX call to /'+errMsg+' function failed');
})
}
JSON данные, возвращаемые из API:
РЕДАКТИРОВАТЬ: Может быть важно: Когда я обращаюсь к API через URL в браузере, он всегда возвращает измененные данные; похоже, мой код изменяет фактические сущности в наборе $ matchCrops. Таким образом, если установить для $ content значение $ MatchCrops или $ cropWithYieldInfo, результат в браузере всегда будет одинаковым. Но он отличается при доступе к API через ajax: когда $ content = json_encoded ($ MatchCrops) я получаю исходный неизмененный массив данных, когда $ content = json_encoded ($ cropWithYieldInfo) я получаю пустой массив.
Это действительно странно: почему браузер всегда получает модифицированный массив, а ajax получает либо один, либо другой ??? Я понимаю, что если я изменяю сущность $ crop, то она изменяет сущность в результирующем наборе, но я ожидаю, что это будет согласованно как для браузера, так и для вызова ajax.
РЕДАКТИРОВАТЬ: я попытался слегка изменить код, позволяющий увидеть, будут ли какие-либо изменения в клонировании сущностей, но единственное отличие состоит в том, что теперь браузер получает то, что я ожидаю (либо исходный неизмененный массив, либо модифицированный), и это согласуется с тем, что получает ajax. Но это не решает проблему (ajax по-прежнему получает пустой массив, если массив был изменен).
foreach($matchingCrops as $crop){
$modCrop = clone $crop;
$availableYield = $this->Crops->calculateAvailableYield($crop->id); //returns a string
if(isset($availableYield) && !empty($availableYield)){
$modCrop->available_yield = number_format($availableYield,1); //tried $crop['available_yield'] as well, same result
$cropsWithYieldInfo[] = $modCrop;
}
}
Modified (ajax получает это как пустой массив; браузер всегда получает это из API):
[{"id":12345,"grower_name":"XYZ","bulk":false,"available_yield":"4.1"},{"id":23456,"grower_name":null,"bulk":true,"available_yield":"190.0"}]
Не изменено (ajax получает это правильно):
[{"id":12345,"grower_name":"XYZ","bulk":false},{"id":23456,"grower_name":null,"bulk":true}]