/**
  * @param TableCell $cell
  * @param bool $includeFormatting
  * @param bool $optimizeNullValues [optional] Default=FALSE
  * @param bool $renderDateAsDateConstructor [optional] Default=TRUE
  * @return string JSON formatted string representing this TableCell
  * @throws NoSuchValueTypeException
  */
 public function renderCellJson(TableCell $cell, $includeFormatting, $optimizeNullValues = false, $renderDateAsDateConstructor = true)
 {
     $value = $cell->getValue();
     $valueType = $cell->getValueType();
     $valueTypeCode = $valueType->getCode();
     $isJsonNull = false;
     $escapedFormattedValue = null;
     $json = "";
     if ($value->isNull()) {
         $json .= "null";
         $isJsonNull = true;
     } else {
         switch ($valueTypeCode) {
             case ValueType::BOOLEAN:
                 $json .= $value->__toString();
                 break;
             case ValueType::NUMBER:
             case ValueType::STRING:
                 if ($value->isNull()) {
                     $json .= "null";
                 } else {
                     $json .= json_encode($value->__toString());
                 }
                 break;
             case ValueType::DATE:
             case ValueType::DATETIME:
                 if ($value->isNull()) {
                     $json .= "null";
                 } else {
                     $date = $value->getRawValue();
                     $year = $date->getYear();
                     $month = $date->getMonth();
                     $day = $date->getMonthDay();
                     $dateValue = "Date({$year},{$month},{$day}";
                     if ($valueTypeCode === ValueType::DATETIME) {
                         $hours = $date->getHours();
                         $mins = $date->getMinutes();
                         $secs = $date->getSeconds();
                         $dateValue .= ",{$hours},{$mins},{$secs}";
                     }
                     $dateValue .= ")";
                     if ($renderDateAsDateConstructor) {
                         $json .= "new " . $dateValue;
                     } else {
                         $json .= "\"" . $dateValue . "\"";
                     }
                 }
                 break;
             case ValueType::TIMEOFDAY:
                 if ($value->isNull()) {
                     $json .= "null";
                 } else {
                     $date = $value->getRawValue();
                     $hours = $date->getHours();
                     $mins = $date->getMinutes();
                     $secs = $date->getSeconds();
                     $millis = $date->getMilliseconds();
                     $json .= "[{$hours},{$mins},{$secs},{$millis}]";
                 }
                 break;
             default:
                 throw new NoSuchValueTypeException($valueTypeCode);
         }
     }
     if ($includeFormatting) {
         $formattedValue = $cell->getFormattedValue();
         if (!$value->isNull() && $formattedValue !== null) {
             // For strings if the value === formattedValue then
             // don't send the formattedValue
             if ($valueTypeCode !== ValueType::STRING || $value->getValue() !== $formattedValue) {
                 $escapedFormattedValue = json_encode($formattedValue);
             }
         }
     }
     // Add a Json for this cell. And,
     // 1) If the formatted value is empty drop it.
     // 2) If the value is null, and it is not the last column in the row drop the entire Json.
     if ($isJsonNull && $optimizeNullValues) {
         $output = "";
     } else {
         $output = "{";
         // Value
         $output .= "\"v\":" . $json;
         // Formatted value
         if ($includeFormatting && $escapedFormattedValue != '') {
             $output .= ",\"f\":" . $escapedFormattedValue;
         }
         // Custom properties
         $customProperties = $this->renderCustomPropertiesString($cell->getCustomProperties());
         if ($customProperties !== null) {
             $output .= ",\"p\":" . $customProperties;
         }
         $output .= "}";
     }
     return $output;
 }
 public function testTableCellValueWithProperties()
 {
     $value = new TextValue('foo');
     $properties = array('a' => 'enabled');
     $cell = new TableCell($value, $value->getRawValue(), $properties);
     $properties = $cell->getCustomProperties();
     $this->assertEquals($value, $cell->getValue(), "Table cell value must match input");
     $this->assertSame($value->getRawValue(), $cell->getFormattedValue(), "Table cell formatted value must match input");
     $this->assertTrue(is_array($properties), "properties must be an array");
     $this->assertArrayHasKey('a', $properties, "properties[a] must exist");
     $this->assertSame($properties['a'], $cell->getCustomProperty('a'), "getCustomProperty must return expected value");
 }