Page MenuHomePhabricator

PhabricatorProjectCustomFields that use storage result in infinite recursion
Closed, ResolvedPublic

Description

I've added custom fields to maniphest and they work fine, but when I try to add them to Projects, any item that uses storage enters an infinite loop when you try to save it.

Reproduce steps:

Place this file in src/extensions, and try to edit a project.

1<?php
2
3final class ProjectCustomField extends PhabricatorProjectCustomField
4 implements PhabricatorStandardCustomFieldInterface {
5
6 public function __construct() {
7 $proxy = id(new PhabricatorStandardCustomFieldDate())
8 ->setFieldKey($this->getFieldKey())
9 ->setApplicationField($this)
10 ->setFieldConfig(array(
11 'name' => $this->getFieldName(),
12 'description' => $this->getFieldDescription(),
13 ));
14
15 $this->setProxy($proxy);
16 }
17
18 public function getStandardCustomFieldNamespace() {
19 return 'project';
20 }
21
22 // == General field identity stuff
23 public function getFieldKey() {
24 return 'sprint:startdate';
25 }
26
27 public function getFieldName() {
28 return 'Sprint Start Date';
29 }
30
31 public function getFieldDescription() {
32 return 'When a sprint starts';
33 }
34
35 public function renderPropertyViewValue(array $handles) {
36 if ($this->getProxy()->getFieldValue())
37 {
38 return parent::renderPropertyViewValue($handles);
39 }
40
41 return null;
42 }
43
44 // == Search
45 public function shouldAppearInApplicationSearch()
46 {
47 return true;
48 }
49
50}

(As a note, I have no idea if setting the proxy in the constructor is the right way, but it seemed to work for maniphest task custom fields)

Results in the error:

>>> UNRECOVERABLE FATAL ERROR <<<

Maximum function nesting level of &#039;100&#039; reached, aborting!

/opt/code/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php:62


┻━┻ ︵ ¯\_(ツ)_/¯ ︵ ┻━┻

More details

Xdebug shows that we are bouncing between PhabricatorCustomField->newStorageObject() and PhabricatorStandardCustomField->newStorageObject()

...
[3] file:///opt/code/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php.PhabricatorStandardCustomField->newStorageObject:233
[4] file:///opt/code/phabricator/src/infrastructure/customfield/field/PhabricatorCustomField.php.PhabricatorCustomField->newStorageObject:526
[5] file:///opt/code/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php.PhabricatorStandardCustomField->newStorageObject:233
[6] file:///opt/code/phabricator/src/infrastructure/customfield/field/PhabricatorCustomField.php.PhabricatorCustomField->newStorageObject:526
[7] file:///opt/code/phabricator/src/infrastructure/customfield/standard/PhabricatorStandardCustomField.php.PhabricatorStandardCustomField->newStorageObject:233
...

Solution

The solution I found was making PhabricatorProjectCustomField add some missing methods that were implemented in ManiphestCustomField:

public function newStorageObject() {
  return new PhabricatorProjectCustomFieldStorage();
}

protected function newStringIndexStorage() {
  return new PhabricatorProjectCustomFieldStringIndex();
}

protected function newNumericIndexStorage() {
  return new PhabricatorProjectCustomFieldNumericIndex();
}

Diff incoming.

Event Timeline

bluehawk raised the priority of this task from to Needs Triage.
bluehawk updated the task description. (Show Details)
bluehawk added a project: Phabricator.
bluehawk added a subscriber: bluehawk.