Skip to content

Instantly share code, notes, and snippets.

@owldesign
Created November 6, 2014 02:38
Show Gist options
  • Save owldesign/545ac8eeb2d8450492a9 to your computer and use it in GitHub Desktop.
Save owldesign/545ac8eeb2d8450492a9 to your computer and use it in GitHub Desktop.
FormBuilder_FieldsService.php
<?php
namespace Craft;
class FormBuilder_FieldsService extends BaseApplicationComponent
{
public $oldFieldColumnPrefix = 'field_';
private $_fieldsById;
private $_allFieldsInContext;
private $_fieldsByContextAndHandle;
private $_fieldsWithContent;
/**
* Returns a field form by its ID.
*
* @param int $formId
*
* @return FieldGroupModel|null
*/
public function getFormById($formId)
{
if (!isset($this->_formsById) || !array_key_exists($formId, $this->_formsById))
{
$result = $this->_createGroupQuery()
->where('id = :id', array(':id' => $formId))
->queryRow();
if ($result)
{
$form = new FormBuilder_FormModel($result);
}
else
{
$form = null;
}
$this->_formsById[$formId] = $form;
}
return $this->_formsById[$formId];
}
// Fields
// -------------------------------------------------------------------------
/**
* Returns all fields.
*
* @param string|null $indexBy
*
* @return array
*/
public function getAllFields($indexBy = null)
{
$context = craft()->formBuilder->fieldContext;
if (!isset($this->_allFieldsInContext[$context]))
{
$results = $this->_createFieldQuery()
->where('context = :context', array(':context' => $context))
->queryAll();
$this->_allFieldsInContext[$context] = array();
foreach ($results as $result)
{
$field = $this->_populateField($result);
$this->_allFieldsInContext[$context][] = $field;
$this->_fieldsById[$field->id] = $field;
$this->_fieldsByContextAndHandle[$context][$field->handle] = $field;
}
}
if (!$indexBy)
{
$fields = $this->_allFieldsInContext[$context];
}
else
{
$fields = array();
foreach ($this->_allFieldsInContext[$context] as $field)
{
$fields[$field->$indexBy] = $field;
}
}
return $fields;
}
/**
* Validates a field's settings.
*
* @param FieldModel $field
*
* @return bool
*/
public function validateField(FormBuilder_FieldModel $field)
{
$fieldRecord = $this->_getFieldRecord($field);
if (!$field->context)
{
$field->context = craft()->content->fieldContext;
}
$fieldRecord->name = $field->name;
$fieldRecord->handle = $field->handle;
$fieldRecord->context = $field->context;
$fieldRecord->instructions = $field->instructions;
$fieldRecord->translatable = $field->translatable;
$fieldRecord->type = $field->type;
// Get the field type
$fieldType = $field->getFieldType();
// Give the field type a chance to prep the settings from post
$preppedSettings = $fieldType->prepSettings($field->settings);
// Set the prepped settings on the FieldRecord and the field type
$fieldRecord->settings = $preppedSettings;
$fieldType->setSettings($preppedSettings);
// Run validation
$recordValidates = $fieldRecord->validate();
$settingsValidate = $fieldType->getSettings()->validate();
if ($recordValidates && $settingsValidate)
{
return true;
}
else
{
$field->addErrors($fieldRecord->getErrors());
$field->addSettingErrors($fieldType->getSettings()->getErrors());
return false;
}
}
/**
* Saves a field.
*
* @param FieldModel $field
* @param bool $validate
*
* @throws \Exception
* @return bool
*/
public function saveField(FormBuilder_FieldModel $field, $validate = true)
{
if (!$validate || $this->validateField($field))
{
$transaction = craft()->db->getCurrentTransaction() === null ? craft()->db->beginTransaction() : null;
try
{
$field->context = craft()->content->fieldContext;
$fieldRecord = $this->_getFieldRecord($field);
$isNewField = $fieldRecord->isNewRecord();
$fieldRecord->groupId = $field->groupId;
$fieldRecord->name = $field->name;
$fieldRecord->handle = $field->handle;
$fieldRecord->context = $field->context;
$fieldRecord->instructions = $field->instructions;
$fieldRecord->translatable = $field->translatable;
$fieldRecord->type = $field->type;
// Get the field type
$fieldType = $field->getFieldType();
// Give the field type a chance to prep the settings from post
$preppedSettings = $fieldType->prepSettings($field->settings);
// Set the prepped settings on the FieldRecord, FieldModel, and the field type
$fieldRecord->settings = $field->settings = $preppedSettings;
$fieldType->setSettings($preppedSettings);
if ($fieldRecord->settings instanceof BaseModel)
{
// Call getAttributes() without passing 'true' so the __model__ isn't saved
$fieldRecord->settings = $fieldRecord->settings->getAttributes();
}
$fieldType->onBeforeSave();
$fieldRecord->save(false);
// Now that we have a field ID, save it on the model
if ($isNewField)
{
$field->id = $fieldRecord->id;
}
// Create/alter the content table column
$columnType = $fieldType->defineContentAttribute();
$contentTable = craft()->content->contentTable;
$oldColumnName = $this->oldFieldColumnPrefix.$fieldRecord->getOldHandle();
$newColumnName = craft()->content->fieldColumnPrefix.$field->handle;
if ($columnType)
{
$columnType = ModelHelper::normalizeAttributeConfig($columnType);
// Make sure we're working with the latest data in the case of a renamed field.
craft()->db->schema->refresh();
if (craft()->db->columnExists($contentTable, $oldColumnName))
{
craft()->db->createCommand()->alterColumn($contentTable, $oldColumnName, $columnType, $newColumnName);
}
else if (craft()->db->columnExists($contentTable, $newColumnName))
{
craft()->db->createCommand()->alterColumn($contentTable, $newColumnName, $columnType);
}
else
{
craft()->db->createCommand()->addColumn($contentTable, $newColumnName, $columnType);
}
}
else
{
// Did the old field have a column we need to remove?
if (!$isNewField)
{
if ($fieldRecord->getOldHandle() && craft()->db->columnExists($contentTable, $oldColumnName))
{
craft()->db->createCommand()->dropColumn($contentTable, $oldColumnName);
}
}
}
if (!$isNewField)
{
// Save the old field handle on the model in case the field type needs to do something with it.
$field->oldHandle = $fieldRecord->getOldHandle();
unset($this->_fieldsByContextAndHandle[$field->context][$field->oldHandle]);
}
// Cache it
$this->_fieldsById[$field->id] = $field;
$this->_fieldsByContextAndHandle[$field->context][$field->handle] = $field;
unset($this->_allFieldsInContext[$field->context]);
unset($this->_fieldsWithContent[$field->context]);
$fieldType->onAfterSave();
if ($transaction !== null)
{
$transaction->commit();
}
}
catch (\Exception $e)
{
if ($transaction !== null)
{
$transaction->rollback();
}
throw $e;
}
return true;
}
else
{
return false;
}
}
/**
* Populates a fieldtype by a field model.
*
* @param FieldModel $field
* @param BaseElementModel|null $element
*
* @return BaseFieldType|null
*/
public function populateFieldType(FormBuilder_FieldModel $field, $element = null)
{
$fieldType = craft()->components->populateComponentByTypeAndModel(ComponentType::Field, $field);
if ($fieldType)
{
$fieldType->element = $element;
return $fieldType;
}
}
/**
* Returns a field record for a given model.
*
* @param FieldModel $field
*
* @throws Exception
* @return FieldRecord
*/
private function _getFieldRecord(FormBuilder_FieldModel $field)
{
if (!$field->isNew())
{
$fieldId = $field->id;
if (!isset($this->_fieldRecordsById) || !array_key_exists($fieldId, $this->_fieldRecordsById))
{
$this->_fieldRecordsById[$fieldId] = FormBuilder_FieldRecord::model()->findById($fieldId);
if (!$this->_fieldRecordsById[$fieldId])
{
throw new Exception(Craft::t('No field exists with the ID “{id}”', array('id' => $fieldId)));
}
}
return $this->_fieldRecordsById[$fieldId];
}
else
{
return new FormBuilder_FieldRecord();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment