BaseFieldDescription.php 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  1. <?php
  2. /*
  3. * This file is part of the Sonata Project package.
  4. *
  5. * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. namespace Sonata\AdminBundle\Admin;
  11. use Doctrine\Common\Inflector\Inflector;
  12. use Sonata\AdminBundle\Exception\NoValueException;
  13. /**
  14. * A FieldDescription hold the information about a field. A typical
  15. * admin instance contains different collections of fields.
  16. *
  17. * - form: used by the form
  18. * - list: used by the list
  19. * - filter: used by the list filter
  20. *
  21. * Some options are global across the different contexts, other are
  22. * context specifics.
  23. *
  24. * Global options :
  25. * - type (m): define the field type (use to tweak the form or the list)
  26. * - template (o) : the template used to render the field
  27. * - name (o) : the name used (label in the form, title in the list)
  28. * - link_parameters (o) : add link parameter to the related Admin class when
  29. * the Admin.generateUrl is called
  30. * - code : the method name to retrieve the related value
  31. * - associated_tostring : (deprecated, use associated_property option)
  32. * the method to retrieve the "string" representation
  33. * of the collection element.
  34. * - associated_property : property path to retrieve the "string" representation
  35. * of the collection element.
  36. *
  37. * Form Field options :
  38. * - field_type (o): the widget class to use to render the field
  39. * - field_options (o): the options to give to the widget
  40. * - edit (o) : list|inline|standard (only used for associated admin)
  41. * - list : open a popup where the user can search, filter and click on one field
  42. * to select one item
  43. * - inline : the associated form admin is embedded into the current form
  44. * - standard : the associated admin is created through a popup
  45. *
  46. * List Field options :
  47. * - identifier (o): if set to true a link appear on to edit the element
  48. *
  49. * Filter Field options :
  50. * - options (o): options given to the Filter object
  51. * - field_type (o): the widget class to use to render the field
  52. * - field_options (o): the options to give to the widget
  53. *
  54. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  55. */
  56. abstract class BaseFieldDescription implements FieldDescriptionInterface
  57. {
  58. /**
  59. * @var string the field name
  60. */
  61. protected $name;
  62. /**
  63. * @var string|int the type
  64. */
  65. protected $type;
  66. /**
  67. * @var string|int the original mapping type
  68. */
  69. protected $mappingType;
  70. /**
  71. * @var string the field name (of the form)
  72. */
  73. protected $fieldName;
  74. /**
  75. * @var array the ORM association mapping
  76. */
  77. protected $associationMapping;
  78. /**
  79. * @var array the ORM field information
  80. */
  81. protected $fieldMapping;
  82. /**
  83. * @var array the ORM parent mapping association
  84. */
  85. protected $parentAssociationMappings;
  86. /**
  87. * @var string the template name
  88. */
  89. protected $template;
  90. /**
  91. * @var array the option collection
  92. */
  93. protected $options = array();
  94. /**
  95. * @var AdminInterface|null the parent Admin instance
  96. */
  97. protected $parent = null;
  98. /**
  99. * @var AdminInterface the related admin instance
  100. */
  101. protected $admin;
  102. /**
  103. * @var AdminInterface the associated admin class if the object is associated to another entity
  104. */
  105. protected $associationAdmin;
  106. /**
  107. * @var string the help message to display
  108. */
  109. protected $help;
  110. /**
  111. * {@inheritdoc}
  112. */
  113. public function setFieldName($fieldName)
  114. {
  115. $this->fieldName = $fieldName;
  116. }
  117. /**
  118. * {@inheritdoc}
  119. */
  120. public function getFieldName()
  121. {
  122. return $this->fieldName;
  123. }
  124. /**
  125. * {@inheritdoc}
  126. */
  127. public function setName($name)
  128. {
  129. $this->name = $name;
  130. if (!$this->getFieldName()) {
  131. $this->setFieldName(substr(strrchr('.'.$name, '.'), 1));
  132. }
  133. }
  134. /**
  135. * {@inheritdoc}
  136. */
  137. public function getName()
  138. {
  139. return $this->name;
  140. }
  141. /**
  142. * {@inheritdoc}
  143. */
  144. public function getOption($name, $default = null)
  145. {
  146. return isset($this->options[$name]) ? $this->options[$name] : $default;
  147. }
  148. /**
  149. * {@inheritdoc}
  150. */
  151. public function setOption($name, $value)
  152. {
  153. $this->options[$name] = $value;
  154. }
  155. /**
  156. * {@inheritdoc}
  157. */
  158. public function setOptions(array $options)
  159. {
  160. // set the type if provided
  161. if (isset($options['type'])) {
  162. $this->setType($options['type']);
  163. unset($options['type']);
  164. }
  165. // remove property value
  166. if (isset($options['template'])) {
  167. $this->setTemplate($options['template']);
  168. unset($options['template']);
  169. }
  170. // set help if provided
  171. if (isset($options['help'])) {
  172. $this->setHelp($options['help']);
  173. unset($options['help']);
  174. }
  175. // set default placeholder
  176. if (!isset($options['placeholder'])) {
  177. $options['placeholder'] = 'short_object_description_placeholder';
  178. }
  179. if (!isset($options['link_parameters'])) {
  180. $options['link_parameters'] = array();
  181. }
  182. $this->options = $options;
  183. }
  184. /**
  185. * {@inheritdoc}
  186. */
  187. public function getOptions()
  188. {
  189. return $this->options;
  190. }
  191. /**
  192. * {@inheritdoc}
  193. */
  194. public function setTemplate($template)
  195. {
  196. $this->template = $template;
  197. }
  198. /**
  199. * {@inheritdoc}
  200. */
  201. public function getTemplate()
  202. {
  203. return $this->template;
  204. }
  205. /**
  206. * {@inheritdoc}
  207. */
  208. public function setType($type)
  209. {
  210. $this->type = $type;
  211. }
  212. /**
  213. * {@inheritdoc}
  214. */
  215. public function getType()
  216. {
  217. return $this->type;
  218. }
  219. /**
  220. * {@inheritdoc}
  221. */
  222. public function setParent(AdminInterface $parent)
  223. {
  224. $this->parent = $parent;
  225. }
  226. /**
  227. * {@inheritdoc}
  228. */
  229. public function getParent()
  230. {
  231. return $this->parent;
  232. }
  233. /**
  234. * {@inheritdoc}
  235. */
  236. public function getAssociationMapping()
  237. {
  238. return $this->associationMapping;
  239. }
  240. /**
  241. * {@inheritdoc}
  242. */
  243. public function getFieldMapping()
  244. {
  245. return $this->fieldMapping;
  246. }
  247. /**
  248. * {@inheritdoc}
  249. */
  250. public function getParentAssociationMappings()
  251. {
  252. return $this->parentAssociationMappings;
  253. }
  254. /**
  255. * {@inheritdoc}
  256. */
  257. public function setAssociationAdmin(AdminInterface $associationAdmin)
  258. {
  259. $this->associationAdmin = $associationAdmin;
  260. $this->associationAdmin->setParentFieldDescription($this);
  261. }
  262. /**
  263. * {@inheritdoc}
  264. */
  265. public function getAssociationAdmin()
  266. {
  267. return $this->associationAdmin;
  268. }
  269. /**
  270. * {@inheritdoc}
  271. */
  272. public function hasAssociationAdmin()
  273. {
  274. return $this->associationAdmin !== null;
  275. }
  276. /**
  277. * {@inheritdoc}
  278. */
  279. public function getFieldValue($object, $fieldName)
  280. {
  281. if ($this->isVirtual()) {
  282. return;
  283. }
  284. $camelizedFieldName = Inflector::classify($fieldName);
  285. $getters = array();
  286. $parameters = array();
  287. // prefer method name given in the code option
  288. if ($this->getOption('code')) {
  289. $getters[] = $this->getOption('code');
  290. }
  291. // parameters for the method given in the code option
  292. if ($this->getOption('parameters')) {
  293. $parameters = $this->getOption('parameters');
  294. }
  295. $getters[] = 'get'.$camelizedFieldName;
  296. $getters[] = 'is'.$camelizedFieldName;
  297. foreach ($getters as $getter) {
  298. if (method_exists($object, $getter)) {
  299. return call_user_func_array(array($object, $getter), $parameters);
  300. }
  301. }
  302. if (method_exists($object, '__call')) {
  303. return call_user_func_array(array($object, '__call'), array($fieldName, $parameters));
  304. }
  305. if (isset($object->{$fieldName})) {
  306. return $object->{$fieldName};
  307. }
  308. throw new NoValueException(sprintf('Unable to retrieve the value of `%s`', $this->getName()));
  309. }
  310. /**
  311. * {@inheritdoc}
  312. */
  313. public function setAdmin(AdminInterface $admin)
  314. {
  315. $this->admin = $admin;
  316. }
  317. /**
  318. * {@inheritdoc}
  319. */
  320. public function getAdmin()
  321. {
  322. return $this->admin;
  323. }
  324. /**
  325. * {@inheritdoc}
  326. */
  327. public function mergeOption($name, array $options = array())
  328. {
  329. if (!isset($this->options[$name])) {
  330. $this->options[$name] = array();
  331. }
  332. if (!is_array($this->options[$name])) {
  333. throw new \RuntimeException(sprintf('The key `%s` does not point to an array value', $name));
  334. }
  335. $this->options[$name] = array_merge($this->options[$name], $options);
  336. }
  337. /**
  338. * {@inheritdoc}
  339. */
  340. public function mergeOptions(array $options = array())
  341. {
  342. $this->setOptions(array_merge_recursive($this->options, $options));
  343. }
  344. /**
  345. * {@inheritdoc}
  346. */
  347. public function setMappingType($mappingType)
  348. {
  349. $this->mappingType = $mappingType;
  350. }
  351. /**
  352. * {@inheritdoc}
  353. */
  354. public function getMappingType()
  355. {
  356. return $this->mappingType;
  357. }
  358. /**
  359. * Camelize a string.
  360. *
  361. * NEXT_MAJOR: remove this method.
  362. *
  363. * @static
  364. *
  365. * @param string $property
  366. *
  367. * @return string
  368. *
  369. * @deprecated Deprecated since version 3.1. Use \Doctrine\Common\Inflector\Inflector::classify() instead
  370. */
  371. public static function camelize($property)
  372. {
  373. @trigger_error(
  374. sprintf(
  375. 'The %s method is deprecated since 3.1 and will be removed in 4.0. '.
  376. 'Use \Doctrine\Common\Inflector\Inflector::classify() instead.',
  377. __METHOD__
  378. ),
  379. E_USER_DEPRECATED
  380. );
  381. return Inflector::classify($property);
  382. }
  383. /**
  384. * Defines the help message.
  385. *
  386. * @param string $help
  387. */
  388. public function setHelp($help)
  389. {
  390. $this->help = $help;
  391. }
  392. /**
  393. * {@inheritdoc}
  394. */
  395. public function getHelp()
  396. {
  397. return $this->help;
  398. }
  399. /**
  400. * {@inheritdoc}
  401. */
  402. public function getLabel()
  403. {
  404. return $this->getOption('label');
  405. }
  406. /**
  407. * {@inheritdoc}
  408. */
  409. public function isSortable()
  410. {
  411. return false !== $this->getOption('sortable', false);
  412. }
  413. /**
  414. * {@inheritdoc}
  415. */
  416. public function getSortFieldMapping()
  417. {
  418. return $this->getOption('sort_field_mapping');
  419. }
  420. /**
  421. * {@inheritdoc}
  422. */
  423. public function getSortParentAssociationMapping()
  424. {
  425. return $this->getOption('sort_parent_association_mappings');
  426. }
  427. /**
  428. * {@inheritdoc}
  429. */
  430. public function getTranslationDomain()
  431. {
  432. return $this->getOption('translation_domain') ?: $this->getAdmin()->getTranslationDomain();
  433. }
  434. /**
  435. * Return true if field is virtual.
  436. *
  437. * @return bool
  438. */
  439. public function isVirtual()
  440. {
  441. return false !== $this->getOption('virtual_field', false);
  442. }
  443. }