I am trying to update a CustomField using a PHP script, but run into some unexpected trouble.
I had a peek at `processRequest()` in `phabricator/src/applications/people/controller/PhabricatorPeopleProfileEditController.php` and then modelled my code after `buildFieldTransactionsFromRequest()` from `phabricator/src/infrastructure/customfield/field/PhabricatorCustomFieldList.php`.
Thus my code looks like this:
```lang=php
function setUserField($user, $field_key, $field_value, $viewer) {
$fields = PhabricatorCustomField::getObjectFields($user, PhabricatorCustomField::ROLE_DEFAULT)
->setViewer($viewer)
->readFieldsFromStorage($user)
->getFields();
$field = idx($fields, $field_key);
$transaction_type = $field->getApplicationTransactionType();
$xaction = id(new PhabricatorUserTransaction())
->setTransactionType($transaction_type);
if ($transaction_type == PhabricatorTransactions::TYPE_CUSTOMFIELD) {
// For TYPE_CUSTOMFIELD transactions only, we provide the old value
// as an input.
$old_value = $field->getOldValueForApplicationTransactions();
$xaction->setOldValue($old_value);
}
$field->getProxy()->setFieldValue($field_value);
$new_value = $field->getNewValueForApplicationTransactions();
$xaction->setNewValue($new_value);
if ($transaction_type == PhabricatorTransactions::TYPE_CUSTOMFIELD) {
// For TYPE_CUSTOMFIELD transactions, add the field key in metadata.
$xaction->setMetadataValue('customfield:key', $field->getFieldKey());
}
$metadata = $field->getApplicationTransactionMetadata();
foreach ($metadata as $key => $value) {
$xaction->setMetadataValue($key, $value);
}
$xactions[] = $xaction;
$editor = id(new PhabricatorUserProfileEditor())
->setActor($viewer)
->setContentSource(PhabricatorContentSource::newConsoleSource())
->setContinueOnNoEffect(true)
->setContinueOnMissingFields(true)
->applyTransactions($user, $xactions);
}
```
I retrieve and change the users like this:
```lang=php
$phab_users = id(new PhabricatorPeopleQuery())
->setViewer($phab_admin)
->withIsSystemAgent(false)
->withIsMailingList(false)
->execute();
foreach ($phab_users as $user) {
$user->loadUserProfile();
setUserField($user, "std:user:mycustomfield", 1234, $phab_admin);
}
```
This is almost the same as in the files I referenced above, but I always get an error:
```
# ./phabricator-apply-policy.php
[2015-06-11 21:47:06] EXCEPTION: (AphrontQueryException) #1048: Column 'title' cannot be null at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:311]
arcanist(head=master, ref.master=7d15b85a1bc0), libphremoteuser(head=master, ref.master=1def4e2d7f07), phabricator(head=master, ref.master=146e2baa2032), phutil(head=master, ref.master=92882eb9404d), sprint(head=master, ref.master=ecd2a064d3c2)
#0 AphrontBaseMySQLDatabaseConnection::throwQueryCodeException(integer, string) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:275]
#1 AphrontBaseMySQLDatabaseConnection::throwQueryException(mysqli) called at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:181]
#2 AphrontBaseMySQLDatabaseConnection::executeRawQuery(string) called at [<phutil>/src/xsprintf/queryfx.php:6]
#3 queryfx(AphrontMySQLiDatabaseConnection, string, string, string, array, string)
#4 call_user_func_array(string, array) called at [<phutil>/src/aphront/storage/connection/AphrontDatabaseConnection.php:26]
#5 AphrontDatabaseConnection::query(string, string, string, array, string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1261]
#6 LiskDAO::insertRecordIntoDatabase(string) called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1106]
#7 LiskDAO::insert() called at [<phabricator>/src/infrastructure/storage/lisk/LiskDAO.php:1075]
#8 LiskDAO::save() called at [<phabricator>/src/applications/people/storage/PhabricatorUser.php:269]
#9 PhabricatorUser::save() called at [<phabricator>/src/applications/transactions/editor/PhabricatorApplicationTransactionEditor.php:843]
#10 PhabricatorApplicationTransactionEditor::applyTransactions(PhabricatorUser, array) called at [<phabricator>-apply-policy/phabricator-apply-policy.inc.php:79]
#11 setUserField(PhabricatorUser, string, integer, PhabricatorUser) called at [<phabricator>-apply-policy/phabricator-apply-policy.inc.php:150]
#12 apply_policies_to_users(array, array) called at [<phabricator>-apply-policy/phabricator-apply-policy.php:49]
PHP Fatal error: Uncaught exception 'Exception' with message 'Process exited with an open transaction! The transaction will be implicitly rolled back. Calls to openTransaction() must always be paired with a call to saveTransaction() or killTransaction().' in /opt/phabricator/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php:78
Stack trace:
#0 [internal function]: AphrontDatabaseTransactionState->__destruct()
#1 {main}
thrown in /opt/phabricator/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 78
Fatal error: Uncaught exception 'Exception' with message 'Process exited with an open transaction! The transaction will be implicitly rolled back. Calls to openTransaction() must always be paired with a call to saveTransaction() or killTransaction().' in /opt/phabricator/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php:78
Stack trace:
#0 [internal function]: AphrontDatabaseTransactionState->__destruct()
#1 {main}
thrown in /opt/phabricator/libphutil/src/aphront/storage/connection/AphrontDatabaseTransactionState.php on line 78
```
Under some circumstances the user or the transaction seems to be malformed. But I don't yet see why.