(NOTE) **Preempting Disclaimer:** Yes we know we're off in experimental territory by merrily using edit engines for our own devices. We don't have a whole lot of them yet, but they are fun and useful to us since it's super common that people want both API and web interface support for the types of things we build here.
A scenario that has cropped up a few times is that when creating some type of object, there are attributes that can be set during creation, but should not be modified when editing. We found a way to support this that //seems// to be mostly inline with the intended function of the extension points / subclass structure, but was also awkward and obtuse enough that I could easily see it being clobbered in the near future. I also don't see any examples of this in Phacility code anywhere, which further makes me believe we're on shaky ground / wouldn't be able to "follow the leader" from upstream refactors of similar code.
A verbatim example is below. We've defined a release product, similar in purpose to the concept of a product in releeph. The product must have a repository associated with it when it's created, but you shouldn't be permitted to change the repository of a product after the fact. The edit engine definition below seems to behave as we want from the web and from the API.
```lang=php
<?php
final class CIReleaseProductEditEngine
extends CIReleaseEditEngine {
const ENGINECONST = 'gauntlet.product';
const EDITENGINECONFIG_EDIT = 'edit';
public function getEngineName() {
return pht('Release Products');
}
protected function getObjectName() {
return pht('Product');
}
protected function newEditableObject() {
return CIReleaseProduct::initializeNewProduct();
}
protected function newObjectQuery() {
return new CIReleaseProductQuery();
}
protected function getObjectCreateTitleText($object) {
return pht('Create New Product');
}
protected function getObjectEditTitleText($object) {
return pht('Edit %s', $object->getName());
}
protected function getObjectEditShortText($object) {
return $object->getName();
}
protected function getObjectCreateShortText() {
return pht('Create Product');
}
protected function newBuiltinEngineConfigurations() {
$create = $this->newConfiguration()
->setBuiltinKey(self::EDITENGINECONFIG_DEFAULT)
->setIsEdit(false)
->setIsDefault(true)
->setName($this->getObjectCreateShortText());
$edit = $this->newConfiguration()
->setBuiltinKey(self::EDITENGINECONFIG_EDIT)
->setIsEdit(true)
->setIsDefault(false)
->setFieldLocks([
'repository' => PhabricatorEditEngineConfiguration::LOCK_LOCKED,
]);
return array(
$create,
$edit,
);
}
protected function buildCustomEditFields($object) {
$repository_field = (new CIRepositoryEditField())
->setKey('repository')
->setLabel(pht('Repository'))
->setDescription(pht('Repository this product is produced from.'))
->setConduitTypeDescription(pht('PHID of a repository.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_REPOSITORY)
->setIsRequired(true)
->setSingleValue($object->getRepositoryPHID());
return array(
$repository_field,
id(new PhabricatorTextEditField())
->setKey('name')
->setLabel(pht('Name'))
->setDescription(pht('Product name.'))
->setConduitDescription(pht('Rename the product.'))
->setConduitTypeDescription(pht('New product name.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_NAME)
->setValue($object->getName()),
id(new PhabricatorTextEditField())
->setKey('slug')
->setLabel(pht('Slug'))
->setDescription(pht('Product slug.'))
->setConduitDescription(pht('Change the product slug.'))
->setConduitTypeDescription(pht('New product slug.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_SLUG)
->setValue($object->getSlug()),
id(new PhabricatorRemarkupEditField())
->setKey('description')
->setLabel(pht('Description'))
->setDescription(pht('Product description.'))
->setConduitDescription(pht('Change product description.'))
->setConduitTypeDescription(pht('New product description.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_DESCRIPTION)
->setValue($object->getDescription()),
id(new PhabricatorSelectEditField())
->setKey('status')
->setLabel(pht('Status'))
->setDescription(pht('Product status.'))
->setConduitDescription(pht('Change product statuc.'))
->setConduitTypeDescription(pht('New product status constant.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_STATUS)
->setValue($object->getStatus())
->setOptions(CIReleaseProduct::getStatusNameMap()),
id(new PhabricatorSelectEditField())
->setKey('strategy')
->setLabel(pht('Naming Strategy'))
->setDescription(pht('Product naming strategy.'))
->setConduitDescription(pht('Change product naming convention.'))
->setConduitTypeDescription(pht('New product naming strategy constant.'))
->setTransactionType(CIReleaseProductTransaction::TYPE_STRATEGY)
->setValue($object->getNamingStrategyKey())
->setOptions(CIReleaseNamingStrategy::getNamingStrategyMap()),
);
}
}
```
My question is, would you suggest a different way of doing this?