/**
  * @param \DataObject $object
  * @param Field $field
  */
 public function write(\DataObject $object, Field $field)
 {
     $className = $object->class;
     // cache has_extension call
     if (!isset($this->isVersioned[$className])) {
         $this->isVersioned[$className] = $object->has_extension('Versioned');
     }
     if ($this->isVersioned[$className]) {
         $args = $field->options;
         if (!isset($args['publish']) || $args['publish']) {
             $this->batchWriter->writeToStage($object, 'Stage', 'Live');
         } else {
             $this->batchWriter->writeToStage($object, 'Stage');
         }
     } else {
         $this->batchWriter->write($object);
     }
     $isSeeded = $object->isSeeded();
     if (!$isSeeded) {
         $isRoot = $field->fieldType === Field::FT_ROOT;
         $dataObjectProperty = $this->dataObjectRecordProperty;
         $batchWriter = $this->batchWriter;
         $object->onAfterExistsCallback(function ($object) use($field, $isRoot, $dataObjectProperty, $batchWriter) {
             $seed = \QuickDataObject::create('SeedRecord');
             $objectFields = $dataObjectProperty->getValue($object);
             $fields = $dataObjectProperty->getValue($seed);
             $fields['SeedClassName'] = $object->class;
             $fields['SeedID'] = $objectFields['ID'];
             $fields['Key'] = $field->key;
             $fields['Root'] = $isRoot;
             $dataObjectProperty->setValue($seed, $fields);
             $batchWriter->write($seed);
         });
         $object->setIsSeeded();
     }
 }
 /**
  * @param $field
  * @param $upState
  * @param int $index
  * @return mixed
  */
 protected function generateObject($field, $upState, $index = 0)
 {
     $className = $field->dataType;
     $object = \QuickDataObject::create($className);
     $state = $upState->down($field, $object, $index);
     foreach ($field->fields as $objectField) {
         if ($objectField->ignore) {
             continue;
         }
         $values = $objectField->provider->generate($objectField, $state);
         if (!empty($values)) {
             $object->setField($objectField->fieldName, $values[0]);
         }
     }
     $writer = $this->writer;
     $hasOneIsAncestor = false;
     $afterHasOneExists = new \OnAfterExists(function () use($object, $field, $writer) {
         $writer->write($object, $field);
     });
     foreach ($field->hasOne as $hasOneField) {
         if ($hasOneField->ignore) {
             continue;
         }
         $values = $hasOneField->provider->generate($hasOneField, $state);
         if (!empty($values[0])) {
             $value = $values[0];
             $relation = $hasOneField->fieldName;
             $hasOneIsAncestor = $hasOneIsAncestor || $state->isAncestor($value);
             $afterHasOneExists->addCondition($values[0], function ($value) use($object, $relation) {
                 $object->setField($relation, $value->getField('ID'));
             });
         }
     }
     foreach ($field->manyMany as $manyManyField) {
         if ($manyManyField->ignore) {
             continue;
         }
         $values = $manyManyField->provider->generate($manyManyField, $state);
         if (!empty($values)) {
             $relation = $manyManyField->methodName;
             $afterExists = new \OnAfterExists(function () use($object, $relation, $values, $writer) {
                 $writer->writeManyMany($object, $relation, $values);
             });
             $afterExists->addCondition($object);
             $afterExists->addCondition($values);
         }
     }
     foreach ($field->hasMany as $hasManyField) {
         if ($hasManyField->ignore) {
             continue;
         }
         $values = $hasManyField->provider->generate($hasManyField, $state);
         if (!empty($values)) {
             $object->onAfterExistsCallback(function ($object) use($values, $writer, $hasManyField) {
                 $relation = '';
                 foreach ($values[0]->has_one() as $fieldName => $className) {
                     if ($object instanceof $className) {
                         $relation = $fieldName . 'ID';
                     }
                 }
                 if ($relation) {
                     $id = $object->getField('ID');
                     foreach ($values as $value) {
                         // set has_many field to object ID
                         $value->setField($relation, $id);
                         $writer->write($value, $hasManyField);
                     }
                 }
             });
         }
     }
     // only write object when it won't already be written when has_one fields are written
     // unless there is a dependency write loop, then write first
     // don't write has many fields since they will be written once their owner is written
     if ((!$afterHasOneExists->count() || $hasOneIsAncestor) && $field->fieldType !== Field::FT_HAS_MANY) {
         $this->writer->write($object, $field);
     }
     return $object;
 }