/**
  * @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;
 }
 /**
  *
  */
 public function testWriteManyMany_SetChildrenForParent_RelationWritten()
 {
     $parent = new Human();
     $parent->Name = 'Bob';
     $children = array();
     for ($i = 0; $i < 5; $i++) {
         $child = new Child();
         $child->Name = 'Soldier #' . $i;
         $children[] = $child;
     }
     $writer = new \BatchedWriter();
     $afterExists = new \OnAfterExists(function () use($writer, $parent, $children) {
         $writer->writeManyMany($parent, 'Children', $children);
     });
     $afterExists->addCondition($parent);
     $afterExists->addCondition($children);
     $writer->write(array($parent));
     $writer->write($children);
     $writer->finish();
     $parent = Human::get()->first();
     $this->assertEquals(5, $parent->Children()->Count());
 }
 /**
  *
  */
 public function testWriteManyMany_WriteManyManyObjects_ObjectsAccessibleFromManyMany()
 {
     $this->markTestIncomplete('Need silverstripe-batchwrite compatibility.');
     $batchSizes = array(10, 30, 100, 300);
     foreach ($batchSizes as $batchSize) {
         $writer = new BatchedSeedWriter($batchSize);
         for ($i = 0; $i < 10; $i++) {
             $owner = new Human();
             $owner->Name = 'Mr bean ' . $i;
             for ($j = 0; $j < 10; $j++) {
                 $dog = new Dog();
                 $dog->Name = 'Walnut ' . $i;
                 $afterExists = new \OnAfterExists(function () use($owner, $dog, $writer) {
                     $writer->writeManyMany($owner, 'Pets', $dog);
                 });
                 $afterExists->addCondition($owner);
                 $afterExists->addCondition($dog);
                 $writer->write($dog, $this->createField());
             }
             $writer->write($owner, $this->createField());
         }
         $writer->finish();
         $owners = Human::get();
         $dogs = Dog::get();
         $this->assertEquals(10, $owners->Count());
         $this->assertEquals(100, $dogs->Count());
         foreach ($owners as $owner) {
             $this->assertEquals(10, $owner->Pets()->Count());
         }
         $writer->delete($owners);
         $writer->delete($dogs);
         $writer->finish();
     }
 }
 /**
  *
  */
 public function testOnAfterExists_ArrayCondition_CalledBack()
 {
     $parent = new Human();
     $parent->Name = 'Bob';
     $children = array();
     for ($i = 0; $i < 5; $i++) {
         $child = new Child();
         $child->Name = 'Soldier #' . $i;
         $children[] = $child;
     }
     $batch = new \Batch();
     $afterExists = new \OnAfterExists(function () use($batch, $parent, $children) {
         $sets = array();
         foreach ($children as $child) {
             $sets[] = array($parent, 'Children', $child);
         }
         $batch->writeManyMany($sets);
     });
     $afterExists->addCondition($parent);
     $afterExists->addCondition($children);
     $batch->write(array($parent));
     $batch->write($children);
     $parent = Human::get()->first();
     $this->assertEquals(5, $parent->Children()->Count());
 }