| @@ -229,9 +229,22 @@ | ||
| 229 | 229 | return self::getUploadedFileUrl(Arr::get(self::$store['custom_booking_data'], $key)); |
| 230 | 230 | } |
| 231 | 231 | |
| 232 | 232 | if (Arr::get($customField, 'type') == 'hidden') { |
| 233 | - return self::parseShortCodes(Arr::get(self::$store['custom_booking_data'], $key)); | |
| 233 | + static $resolving = []; | |
| 234 | + | |
| 235 | + // Guest-supplied hidden values are parsed again, so a self-reference would recurse until the stack runs out. | |
| 236 | + if (isset($resolving[$key])) { | |
| 237 | + return Arr::get(self::$store['custom_booking_data'], $key); | |
| 238 | + } | |
| 239 | + | |
| 240 | + $resolving[$key] = true; | |
| 241 | + | |
| 242 | + try { | |
| 243 | + return self::parseShortCodes(Arr::get(self::$store['custom_booking_data'], $key)); | |
| 244 | + } finally { | |
| 245 | + unset($resolving[$key]); | |
| 246 | + } | |
| 234 | 247 | } |
| 235 | 248 | |
| 236 | 249 | return Arr::get(self::$store['custom_booking_data'], $key); |
| 237 | 250 | } |
| @@ -292,9 +305,9 @@ | ||
| 292 | 305 | if ($key == 'form_data_html') { |
| 293 | 306 | return __('will be available soon', 'fluent-booking'); |
| 294 | 307 | } |
| 295 | 308 | |
| 296 | - return Arr::get($guest, $key, ''); | |
| 309 | + return self::resolveScalarAttribute($guest, $key); | |
| 297 | 310 | } |
| 298 | 311 | |
| 299 | 312 | protected static function getBookingEventData($key) |
| 300 | 313 | { |
| @@ -305,13 +318,13 @@ | ||
| 305 | 318 | } |
| 306 | 319 | |
| 307 | 320 | $fillables = (new CalendarSlot())->getFillable(); |
| 308 | 321 | |
| 309 | - if (in_array($key, $fillables) || isset($bookingEvent->{$key})) { | |
| 322 | + if (in_array($key, $fillables)) { | |
| 310 | 323 | return $bookingEvent->{$key}; |
| 311 | 324 | } |
| 312 | 325 | |
| 313 | - return ''; | |
| 326 | + return self::resolveScalarAttribute($bookingEvent, $key); | |
| 314 | 327 | } |
| 315 | 328 | |
| 316 | 329 | protected static function getCalendarData($key) |
| 317 | 330 | { |
| @@ -322,13 +335,28 @@ | ||
| 322 | 335 | } |
| 323 | 336 | |
| 324 | 337 | $fillables = (new Calendar())->getFillable(); |
| 325 | 338 | |
| 326 | - if (in_array($key, $fillables) || isset($calendar->{$key})) { | |
| 339 | + if (in_array($key, $fillables)) { | |
| 327 | 340 | return $calendar->{$key}; |
| 328 | 341 | } |
| 329 | 342 | |
| 330 | - return ''; | |
| 343 | + return self::resolveScalarAttribute($calendar, $key); | |
| 344 | + } | |
| 345 | + | |
| 346 | + /** | |
| 347 | + * Resolve a scalar attribute only; never a relation (dumps as JSON) or a | |
| 348 | + * dotted hop into a relation's columns. | |
| 349 | + */ | |
| 350 | + protected static function resolveScalarAttribute($model, $key) | |
| 351 | + { | |
| 352 | + if (strpos($key, '.') !== false) { | |
| 353 | + return ''; | |
| 354 | + } | |
| 355 | + | |
| 356 | + $value = isset($model[$key]) ? $model[$key] : ''; | |
| 357 | + | |
| 358 | + return is_scalar($value) ? $value : ''; | |
| 331 | 359 | } |
| 332 | 360 | |
| 333 | 361 | protected static function getPaymentData($key) |
| 334 | 362 | { |