AbstractAdmin.php 73 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895289628972898289929002901290229032904290529062907290829092910291129122913291429152916291729182919292029212922292329242925292629272928292929302931293229332934293529362937293829392940294129422943294429452946294729482949295029512952295329542955295629572958295929602961296229632964296529662967296829692970297129722973297429752976297729782979298029812982298329842985298629872988298929902991299229932994299529962997299829993000300130023003300430053006300730083009301030113012301330143015301630173018301930203021302230233024302530263027302830293030303130323033303430353036303730383039304030413042304330443045304630473048304930503051305230533054305530563057305830593060306130623063306430653066306730683069307030713072307330743075307630773078307930803081308230833084308530863087308830893090309130923093309430953096309730983099310031013102310331043105310631073108310931103111311231133114311531163117311831193120312131223123312431253126312731283129
  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\Util\ClassUtils;
  12. use Knp\Menu\FactoryInterface as MenuFactoryInterface;
  13. use Knp\Menu\ItemInterface;
  14. use Knp\Menu\ItemInterface as MenuItemInterface;
  15. use Sonata\AdminBundle\Builder\DatagridBuilderInterface;
  16. use Sonata\AdminBundle\Builder\FormContractorInterface;
  17. use Sonata\AdminBundle\Builder\ListBuilderInterface;
  18. use Sonata\AdminBundle\Builder\RouteBuilderInterface;
  19. use Sonata\AdminBundle\Builder\ShowBuilderInterface;
  20. use Sonata\AdminBundle\Datagrid\DatagridInterface;
  21. use Sonata\AdminBundle\Datagrid\DatagridMapper;
  22. use Sonata\AdminBundle\Datagrid\ListMapper;
  23. use Sonata\AdminBundle\Datagrid\Pager;
  24. use Sonata\AdminBundle\Datagrid\ProxyQueryInterface;
  25. use Sonata\AdminBundle\Form\FormMapper;
  26. use Sonata\AdminBundle\Model\ModelManagerInterface;
  27. use Sonata\AdminBundle\Route\RouteCollection;
  28. use Sonata\AdminBundle\Route\RouteGeneratorInterface;
  29. use Sonata\AdminBundle\Security\Handler\AclSecurityHandlerInterface;
  30. use Sonata\AdminBundle\Security\Handler\SecurityHandlerInterface;
  31. use Sonata\AdminBundle\Show\ShowMapper;
  32. use Sonata\AdminBundle\Translator\LabelTranslatorStrategyInterface;
  33. use Sonata\CoreBundle\Model\Metadata;
  34. use Sonata\CoreBundle\Validator\Constraints\InlineConstraint;
  35. use Sonata\CoreBundle\Validator\ErrorElement;
  36. use Symfony\Component\Form\Form;
  37. use Symfony\Component\Form\FormBuilderInterface;
  38. use Symfony\Component\HttpFoundation\Request;
  39. use Symfony\Component\PropertyAccess\PropertyPath;
  40. use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
  41. use Symfony\Component\Security\Acl\Model\DomainObjectInterface;
  42. use Symfony\Component\Security\Core\Exception\AccessDeniedException;
  43. use Symfony\Component\Translation\TranslatorInterface;
  44. use Symfony\Component\Validator\Validator\ValidatorInterface;
  45. use Symfony\Component\Validator\ValidatorInterface as LegacyValidatorInterface;
  46. /**
  47. * @author Thomas Rabaix <thomas.rabaix@sonata-project.org>
  48. */
  49. abstract class AbstractAdmin implements AdminInterface, DomainObjectInterface
  50. {
  51. const CONTEXT_MENU = 'menu';
  52. const CONTEXT_DASHBOARD = 'dashboard';
  53. const CLASS_REGEX =
  54. '@
  55. (?:([A-Za-z0-9]*)\\\)? # vendor name / app name
  56. (Bundle\\\)? # optional bundle directory
  57. ([A-Za-z0-9]+?)(?:Bundle)?\\\ # bundle name, with optional suffix
  58. (
  59. Entity|Document|Model|PHPCR|CouchDocument|Phpcr|
  60. Doctrine\\\Orm|Doctrine\\\Phpcr|Doctrine\\\MongoDB|Doctrine\\\CouchDB
  61. )\\\(.*)@x';
  62. /**
  63. * The list FieldDescription constructed from the configureListField method.
  64. *
  65. * @var array
  66. */
  67. protected $listFieldDescriptions = array();
  68. /**
  69. * The show FieldDescription constructed from the configureShowFields method.
  70. *
  71. * @var array
  72. */
  73. protected $showFieldDescriptions = array();
  74. /**
  75. * The list FieldDescription constructed from the configureFormField method.
  76. *
  77. * @var array
  78. */
  79. protected $formFieldDescriptions = array();
  80. /**
  81. * The filter FieldDescription constructed from the configureFilterField method.
  82. *
  83. * @var array
  84. */
  85. protected $filterFieldDescriptions = array();
  86. /**
  87. * The number of result to display in the list.
  88. *
  89. * @var int
  90. */
  91. protected $maxPerPage = 32;
  92. /**
  93. * The maximum number of page numbers to display in the list.
  94. *
  95. * @var int
  96. */
  97. protected $maxPageLinks = 25;
  98. /**
  99. * The base route name used to generate the routing information.
  100. *
  101. * @var string
  102. */
  103. protected $baseRouteName;
  104. /**
  105. * The base route pattern used to generate the routing information.
  106. *
  107. * @var string
  108. */
  109. protected $baseRoutePattern;
  110. /**
  111. * The base name controller used to generate the routing information.
  112. *
  113. * @var string
  114. */
  115. protected $baseControllerName;
  116. /**
  117. * The label class name (used in the title/breadcrumb ...).
  118. *
  119. * @var string
  120. */
  121. protected $classnameLabel;
  122. /**
  123. * The translation domain to be used to translate messages.
  124. *
  125. * @var string
  126. */
  127. protected $translationDomain = 'messages';
  128. /**
  129. * Options to set to the form (ie, validation_groups).
  130. *
  131. * @var array
  132. */
  133. protected $formOptions = array();
  134. /**
  135. * Default values to the datagrid.
  136. *
  137. * @var array
  138. */
  139. protected $datagridValues = array(
  140. '_page' => 1,
  141. '_per_page' => 32,
  142. );
  143. /**
  144. * Predefined per page options.
  145. *
  146. * @var array
  147. */
  148. protected $perPageOptions = array(16, 32, 64, 128, 192);
  149. /**
  150. * Pager type.
  151. *
  152. * @var string
  153. */
  154. protected $pagerType = Pager::TYPE_DEFAULT;
  155. /**
  156. * The code related to the admin.
  157. *
  158. * @var string
  159. */
  160. protected $code;
  161. /**
  162. * The label.
  163. *
  164. * @var string
  165. */
  166. protected $label;
  167. /**
  168. * Whether or not to persist the filters in the session.
  169. *
  170. * @var bool
  171. */
  172. protected $persistFilters = false;
  173. /**
  174. * Array of routes related to this admin.
  175. *
  176. * @var RouteCollection
  177. */
  178. protected $routes;
  179. /**
  180. * The subject only set in edit/update/create mode.
  181. *
  182. * @var object
  183. */
  184. protected $subject;
  185. /**
  186. * Define a Collection of child admin, ie /admin/order/{id}/order-element/{childId}.
  187. *
  188. * @var array
  189. */
  190. protected $children = array();
  191. /**
  192. * Reference the parent collection.
  193. *
  194. * @var AdminInterface|null
  195. */
  196. protected $parent = null;
  197. /**
  198. * The base code route refer to the prefix used to generate the route name.
  199. *
  200. * @var string
  201. */
  202. protected $baseCodeRoute = '';
  203. /**
  204. * The related field reflection, ie if OrderElement is linked to Order,
  205. * then the $parentReflectionProperty must be the ReflectionProperty of
  206. * the order (OrderElement::$order).
  207. *
  208. * @var \ReflectionProperty
  209. */
  210. protected $parentAssociationMapping = null;
  211. /**
  212. * Reference the parent FieldDescription related to this admin
  213. * only set for FieldDescription which is associated to an Sub Admin instance.
  214. *
  215. * @var FieldDescriptionInterface
  216. */
  217. protected $parentFieldDescription;
  218. /**
  219. * If true then the current admin is part of the nested admin set (from the url).
  220. *
  221. * @var bool
  222. */
  223. protected $currentChild = false;
  224. /**
  225. * The uniqid is used to avoid clashing with 2 admin related to the code
  226. * ie: a Block linked to a Block.
  227. *
  228. * @var string
  229. */
  230. protected $uniqid;
  231. /**
  232. * The Entity or Document manager.
  233. *
  234. * @var ModelManagerInterface
  235. */
  236. protected $modelManager;
  237. /**
  238. * The current request object.
  239. *
  240. * @var \Symfony\Component\HttpFoundation\Request
  241. */
  242. protected $request;
  243. /**
  244. * The translator component.
  245. *
  246. * @var \Symfony\Component\Translation\TranslatorInterface
  247. */
  248. protected $translator;
  249. /**
  250. * The related form contractor.
  251. *
  252. * @var FormContractorInterface
  253. */
  254. protected $formContractor;
  255. /**
  256. * The related list builder.
  257. *
  258. * @var ListBuilderInterface
  259. */
  260. protected $listBuilder;
  261. /**
  262. * The related view builder.
  263. *
  264. * @var ShowBuilderInterface
  265. */
  266. protected $showBuilder;
  267. /**
  268. * The related datagrid builder.
  269. *
  270. * @var DatagridBuilderInterface
  271. */
  272. protected $datagridBuilder;
  273. /**
  274. * @var RouteBuilderInterface
  275. */
  276. protected $routeBuilder;
  277. /**
  278. * The datagrid instance.
  279. *
  280. * @var \Sonata\AdminBundle\Datagrid\DatagridInterface
  281. */
  282. protected $datagrid;
  283. /**
  284. * The router instance.
  285. *
  286. * @var RouteGeneratorInterface
  287. */
  288. protected $routeGenerator;
  289. /**
  290. * The generated breadcrumbs.
  291. *
  292. * @var array
  293. */
  294. protected $breadcrumbs = array();
  295. /**
  296. * @var SecurityHandlerInterface
  297. */
  298. protected $securityHandler = null;
  299. /**
  300. * @var ValidatorInterface|LegacyValidatorInterface
  301. */
  302. protected $validator = null;
  303. /**
  304. * The configuration pool.
  305. *
  306. * @var Pool
  307. */
  308. protected $configurationPool;
  309. /**
  310. * @var MenuItemInterface
  311. */
  312. protected $menu;
  313. /**
  314. * @var MenuFactoryInterface
  315. */
  316. protected $menuFactory;
  317. /**
  318. * @var array
  319. */
  320. protected $loaded = array(
  321. 'view_fields' => false,
  322. 'view_groups' => false,
  323. 'routes' => false,
  324. 'tab_menu' => false,
  325. );
  326. /**
  327. * @var array
  328. */
  329. protected $formTheme = array();
  330. /**
  331. * @var array
  332. */
  333. protected $filterTheme = array();
  334. /**
  335. * @var array
  336. */
  337. protected $templates = array();
  338. /**
  339. * @var AdminExtensionInterface[]
  340. */
  341. protected $extensions = array();
  342. /**
  343. * @var LabelTranslatorStrategyInterface
  344. */
  345. protected $labelTranslatorStrategy;
  346. /**
  347. * Setting to true will enable preview mode for
  348. * the entity and show a preview button in the
  349. * edit/create forms.
  350. *
  351. * @var bool
  352. */
  353. protected $supportsPreviewMode = false;
  354. /**
  355. * Roles and permissions per role.
  356. *
  357. * @var array [role] => array([permission], [permission])
  358. */
  359. protected $securityInformation = array();
  360. protected $cacheIsGranted = array();
  361. protected $listModes = array(
  362. 'list' => array(
  363. 'class' => 'fa fa-list fa-fw',
  364. ),
  365. 'mosaic' => array(
  366. 'class' => 'fa fa-th-large fa-fw',
  367. ),
  368. );
  369. /**
  370. * The Access mapping.
  371. *
  372. * @var array
  373. */
  374. protected $accessMapping = array();
  375. /**
  376. * The class name managed by the admin class.
  377. *
  378. * @var string
  379. */
  380. private $class;
  381. /**
  382. * The subclasses supported by the admin class.
  383. *
  384. * @var array
  385. */
  386. private $subClasses = array();
  387. /**
  388. * The list collection.
  389. *
  390. * @var array
  391. */
  392. private $list;
  393. /**
  394. * @var FieldDescriptionCollection
  395. */
  396. private $show;
  397. /**
  398. * @var Form
  399. */
  400. private $form;
  401. /**
  402. * @var DatagridInterface
  403. */
  404. private $filter;
  405. /**
  406. * The cached base route name.
  407. *
  408. * @var string
  409. */
  410. private $cachedBaseRouteName;
  411. /**
  412. * The cached base route pattern.
  413. *
  414. * @var string
  415. */
  416. private $cachedBaseRoutePattern;
  417. /**
  418. * The form group disposition.
  419. *
  420. * @var array|bool
  421. */
  422. private $formGroups = false;
  423. /**
  424. * The form tabs disposition.
  425. *
  426. * @var array|bool
  427. */
  428. private $formTabs = false;
  429. /**
  430. * The view group disposition.
  431. *
  432. * @var array|bool
  433. */
  434. private $showGroups = false;
  435. /**
  436. * The view tab disposition.
  437. *
  438. * @var array|bool
  439. */
  440. private $showTabs = false;
  441. /**
  442. * The manager type to use for the admin.
  443. *
  444. * @var string
  445. */
  446. private $managerType;
  447. /**
  448. * @param string $code
  449. * @param string $class
  450. * @param string $baseControllerName
  451. */
  452. public function __construct($code, $class, $baseControllerName)
  453. {
  454. $this->code = $code;
  455. $this->class = $class;
  456. $this->baseControllerName = $baseControllerName;
  457. $this->predefinePerPageOptions();
  458. $this->datagridValues['_per_page'] = $this->maxPerPage;
  459. }
  460. /**
  461. * {@inheritdoc}
  462. */
  463. public function getExportFormats()
  464. {
  465. return array(
  466. 'json', 'xml', 'csv', 'xls',
  467. );
  468. }
  469. /**
  470. * @return array
  471. */
  472. public function getExportFields()
  473. {
  474. $fields = $this->getModelManager()->getExportFields($this->getClass());
  475. foreach ($this->getExtensions() as $extension) {
  476. if (method_exists($extension, 'configureExportFields')) {
  477. $fields = $extension->configureExportFields($this, $fields);
  478. }
  479. }
  480. return $fields;
  481. }
  482. /**
  483. * {@inheritdoc}
  484. */
  485. public function getDataSourceIterator()
  486. {
  487. $datagrid = $this->getDatagrid();
  488. $datagrid->buildPager();
  489. return $this->getModelManager()->getDataSourceIterator($datagrid, $this->getExportFields());
  490. }
  491. /**
  492. * {@inheritdoc}
  493. */
  494. public function validate(ErrorElement $errorElement, $object)
  495. {
  496. }
  497. /**
  498. * define custom variable.
  499. */
  500. public function initialize()
  501. {
  502. if (!$this->classnameLabel) {
  503. $this->classnameLabel = substr($this->getClass(), strrpos($this->getClass(), '\\') + 1);
  504. }
  505. $this->baseCodeRoute = $this->getCode();
  506. $this->configure();
  507. }
  508. /**
  509. * {@inheritdoc}
  510. */
  511. public function configure()
  512. {
  513. }
  514. /**
  515. * {@inheritdoc}
  516. */
  517. public function update($object)
  518. {
  519. $this->preUpdate($object);
  520. foreach ($this->extensions as $extension) {
  521. $extension->preUpdate($this, $object);
  522. }
  523. $result = $this->getModelManager()->update($object);
  524. // BC compatibility
  525. if (null !== $result) {
  526. $object = $result;
  527. }
  528. $this->postUpdate($object);
  529. foreach ($this->extensions as $extension) {
  530. $extension->postUpdate($this, $object);
  531. }
  532. return $object;
  533. }
  534. /**
  535. * {@inheritdoc}
  536. */
  537. public function create($object)
  538. {
  539. $this->prePersist($object);
  540. foreach ($this->extensions as $extension) {
  541. $extension->prePersist($this, $object);
  542. }
  543. $result = $this->getModelManager()->create($object);
  544. // BC compatibility
  545. if (null !== $result) {
  546. $object = $result;
  547. }
  548. $this->postPersist($object);
  549. foreach ($this->extensions as $extension) {
  550. $extension->postPersist($this, $object);
  551. }
  552. $this->createObjectSecurity($object);
  553. return $object;
  554. }
  555. /**
  556. * {@inheritdoc}
  557. */
  558. public function delete($object)
  559. {
  560. $this->preRemove($object);
  561. foreach ($this->extensions as $extension) {
  562. $extension->preRemove($this, $object);
  563. }
  564. $this->getSecurityHandler()->deleteObjectSecurity($this, $object);
  565. $this->getModelManager()->delete($object);
  566. $this->postRemove($object);
  567. foreach ($this->extensions as $extension) {
  568. $extension->postRemove($this, $object);
  569. }
  570. }
  571. /**
  572. * {@inheritdoc}
  573. */
  574. public function preValidate($object)
  575. {
  576. }
  577. /**
  578. * {@inheritdoc}
  579. */
  580. public function preUpdate($object)
  581. {
  582. }
  583. /**
  584. * {@inheritdoc}
  585. */
  586. public function postUpdate($object)
  587. {
  588. }
  589. /**
  590. * {@inheritdoc}
  591. */
  592. public function prePersist($object)
  593. {
  594. }
  595. /**
  596. * {@inheritdoc}
  597. */
  598. public function postPersist($object)
  599. {
  600. }
  601. /**
  602. * {@inheritdoc}
  603. */
  604. public function preRemove($object)
  605. {
  606. }
  607. /**
  608. * {@inheritdoc}
  609. */
  610. public function postRemove($object)
  611. {
  612. }
  613. /**
  614. * {@inheritdoc}
  615. */
  616. public function preBatchAction($actionName, ProxyQueryInterface $query, array &$idx, $allElements)
  617. {
  618. }
  619. /**
  620. * {@inheritdoc}
  621. */
  622. public function getFilterParameters()
  623. {
  624. $parameters = array();
  625. // build the values array
  626. if ($this->hasRequest()) {
  627. $filters = $this->request->query->get('filter', array());
  628. // if persisting filters, save filters to session, or pull them out of session if no new filters set
  629. if ($this->persistFilters) {
  630. if ($filters == array() && $this->request->query->get('filters') != 'reset') {
  631. $filters = $this->request->getSession()->get($this->getCode().'.filter.parameters', array());
  632. } else {
  633. $this->request->getSession()->set($this->getCode().'.filter.parameters', $filters);
  634. }
  635. }
  636. $parameters = array_merge(
  637. $this->getModelManager()->getDefaultSortValues($this->getClass()),
  638. $this->datagridValues,
  639. $filters
  640. );
  641. if (!$this->determinedPerPageValue($parameters['_per_page'])) {
  642. $parameters['_per_page'] = $this->maxPerPage;
  643. }
  644. // always force the parent value
  645. if ($this->isChild() && $this->getParentAssociationMapping()) {
  646. $name = str_replace('.', '__', $this->getParentAssociationMapping());
  647. $parameters[$name] = array('value' => $this->request->get($this->getParent()->getIdParameter()));
  648. }
  649. }
  650. return $parameters;
  651. }
  652. /**
  653. * {@inheritdoc}
  654. */
  655. public function buildDatagrid()
  656. {
  657. if ($this->datagrid) {
  658. return;
  659. }
  660. $filterParameters = $this->getFilterParameters();
  661. // transform _sort_by from a string to a FieldDescriptionInterface for the datagrid.
  662. if (isset($filterParameters['_sort_by']) && is_string($filterParameters['_sort_by'])) {
  663. if ($this->hasListFieldDescription($filterParameters['_sort_by'])) {
  664. $filterParameters['_sort_by'] = $this->getListFieldDescription($filterParameters['_sort_by']);
  665. } else {
  666. $filterParameters['_sort_by'] = $this->getModelManager()->getNewFieldDescriptionInstance(
  667. $this->getClass(),
  668. $filterParameters['_sort_by'],
  669. array()
  670. );
  671. $this->getListBuilder()->buildField(null, $filterParameters['_sort_by'], $this);
  672. }
  673. }
  674. // initialize the datagrid
  675. $this->datagrid = $this->getDatagridBuilder()->getBaseDatagrid($this, $filterParameters);
  676. $this->datagrid->getPager()->setMaxPageLinks($this->maxPageLinks);
  677. $mapper = new DatagridMapper($this->getDatagridBuilder(), $this->datagrid, $this);
  678. // build the datagrid filter
  679. $this->configureDatagridFilters($mapper);
  680. // ok, try to limit to add parent filter
  681. if ($this->isChild() && $this->getParentAssociationMapping() && !$mapper->has($this->getParentAssociationMapping())) {
  682. $mapper->add($this->getParentAssociationMapping(), null, array(
  683. 'show_filter' => false,
  684. 'label' => false,
  685. 'field_type' => 'sonata_type_model_hidden',
  686. 'field_options' => array(
  687. 'model_manager' => $this->getModelManager(),
  688. ),
  689. 'operator_type' => 'hidden',
  690. ), null, null, array(
  691. 'admin_code' => $this->getParent()->getCode(),
  692. ));
  693. }
  694. foreach ($this->getExtensions() as $extension) {
  695. $extension->configureDatagridFilters($mapper);
  696. }
  697. }
  698. /**
  699. * Returns the name of the parent related field, so the field can be use to set the default
  700. * value (ie the parent object) or to filter the object.
  701. *
  702. * @return string the name of the parent related field
  703. */
  704. public function getParentAssociationMapping()
  705. {
  706. return $this->parentAssociationMapping;
  707. }
  708. /**
  709. * Returns the baseRoutePattern used to generate the routing information.
  710. *
  711. * @throws \RuntimeException
  712. *
  713. * @return string the baseRoutePattern used to generate the routing information
  714. */
  715. public function getBaseRoutePattern()
  716. {
  717. if (null !== $this->cachedBaseRoutePattern) {
  718. return $this->cachedBaseRoutePattern;
  719. }
  720. if ($this->isChild()) { // the admin class is a child, prefix it with the parent route pattern
  721. if (!$this->baseRoutePattern) {
  722. preg_match(self::CLASS_REGEX, $this->class, $matches);
  723. if (!$matches) {
  724. throw new \RuntimeException(sprintf('Please define a default `baseRoutePattern` value for the admin class `%s`', get_class($this)));
  725. }
  726. }
  727. $this->cachedBaseRoutePattern = sprintf('%s/{id}/%s',
  728. $this->getParent()->getBaseRoutePattern(),
  729. $this->baseRoutePattern ?: $this->urlize($matches[5], '-')
  730. );
  731. } elseif ($this->baseRoutePattern) {
  732. $this->cachedBaseRoutePattern = $this->baseRoutePattern;
  733. } else {
  734. preg_match(self::CLASS_REGEX, $this->class, $matches);
  735. if (!$matches) {
  736. throw new \RuntimeException(sprintf('Please define a default `baseRoutePattern` value for the admin class `%s`', get_class($this)));
  737. }
  738. $this->cachedBaseRoutePattern = sprintf('/%s%s/%s',
  739. empty($matches[1]) ? '' : $this->urlize($matches[1], '-').'/',
  740. $this->urlize($matches[3], '-'),
  741. $this->urlize($matches[5], '-')
  742. );
  743. }
  744. return $this->cachedBaseRoutePattern;
  745. }
  746. /**
  747. * Returns the baseRouteName used to generate the routing information.
  748. *
  749. * @throws \RuntimeException
  750. *
  751. * @return string the baseRouteName used to generate the routing information
  752. */
  753. public function getBaseRouteName()
  754. {
  755. if (null !== $this->cachedBaseRouteName) {
  756. return $this->cachedBaseRouteName;
  757. }
  758. if ($this->isChild()) { // the admin class is a child, prefix it with the parent route name
  759. if (!$this->baseRouteName) {
  760. preg_match(self::CLASS_REGEX, $this->class, $matches);
  761. if (!$matches) {
  762. throw new \RuntimeException(sprintf('Cannot automatically determine base route name, please define a default `baseRouteName` value for the admin class `%s`', get_class($this)));
  763. }
  764. }
  765. $this->cachedBaseRouteName = sprintf('%s_%s',
  766. $this->getParent()->getBaseRouteName(),
  767. $this->baseRouteName ?: $this->urlize($matches[5])
  768. );
  769. } elseif ($this->baseRouteName) {
  770. $this->cachedBaseRouteName = $this->baseRouteName;
  771. } else {
  772. preg_match(self::CLASS_REGEX, $this->class, $matches);
  773. if (!$matches) {
  774. throw new \RuntimeException(sprintf('Cannot automatically determine base route name, please define a default `baseRouteName` value for the admin class `%s`', get_class($this)));
  775. }
  776. $this->cachedBaseRouteName = sprintf('admin_%s%s_%s',
  777. empty($matches[1]) ? '' : $this->urlize($matches[1]).'_',
  778. $this->urlize($matches[3]),
  779. $this->urlize($matches[5])
  780. );
  781. }
  782. return $this->cachedBaseRouteName;
  783. }
  784. /**
  785. * urlize the given word.
  786. *
  787. * @param string $word
  788. * @param string $sep the separator
  789. *
  790. * @return string
  791. */
  792. public function urlize($word, $sep = '_')
  793. {
  794. return strtolower(preg_replace('/[^a-z0-9_]/i', $sep.'$1', $word));
  795. }
  796. /**
  797. * {@inheritdoc}
  798. */
  799. public function getClass()
  800. {
  801. // see https://github.com/sonata-project/SonataCoreBundle/commit/247eeb0a7ca7211142e101754769d70bc402a5b4
  802. if ($this->hasSubject() && is_object($this->getSubject())) {
  803. return ClassUtils::getClass($this->getSubject());
  804. }
  805. if (!$this->hasActiveSubClass()) {
  806. if (count($this->getSubClasses()) > 0) {
  807. $subject = $this->getSubject();
  808. if ($subject && is_object($subject)) {
  809. return ClassUtils::getClass($subject);
  810. }
  811. }
  812. return $this->class;
  813. }
  814. if ($this->getParentFieldDescription() && $this->hasActiveSubClass()) {
  815. throw new \RuntimeException('Feature not implemented: an embedded admin cannot have subclass');
  816. }
  817. $subClass = $this->getRequest()->query->get('subclass');
  818. return $this->getSubClass($subClass);
  819. }
  820. /**
  821. * {@inheritdoc}
  822. */
  823. public function getSubClasses()
  824. {
  825. return $this->subClasses;
  826. }
  827. /**
  828. * {@inheritdoc}
  829. */
  830. public function addSubClass($subClass)
  831. {
  832. if (!in_array($subClass, $this->subClasses)) {
  833. $this->subClasses[] = $subClass;
  834. }
  835. }
  836. /**
  837. * {@inheritdoc}
  838. */
  839. public function setSubClasses(array $subClasses)
  840. {
  841. $this->subClasses = $subClasses;
  842. }
  843. /**
  844. * {@inheritdoc}
  845. */
  846. public function hasSubClass($name)
  847. {
  848. return isset($this->subClasses[$name]);
  849. }
  850. /**
  851. * {@inheritdoc}
  852. */
  853. public function hasActiveSubClass()
  854. {
  855. if (count($this->subClasses) > 0 && $this->request) {
  856. return null !== $this->getRequest()->query->get('subclass');
  857. }
  858. return false;
  859. }
  860. /**
  861. * {@inheritdoc}
  862. */
  863. public function getActiveSubClass()
  864. {
  865. if (!$this->hasActiveSubClass()) {
  866. return;
  867. }
  868. return $this->getClass();
  869. }
  870. /**
  871. * {@inheritdoc}
  872. */
  873. public function getActiveSubclassCode()
  874. {
  875. if (!$this->hasActiveSubClass()) {
  876. return;
  877. }
  878. $subClass = $this->getRequest()->query->get('subclass');
  879. if (!$this->hasSubClass($subClass)) {
  880. return;
  881. }
  882. return $subClass;
  883. }
  884. /**
  885. * {@inheritdoc}
  886. */
  887. public function getBatchActions()
  888. {
  889. $actions = array();
  890. if ($this->hasRoute('delete') && $this->isGranted('DELETE')) {
  891. $actions['delete'] = array(
  892. 'label' => 'action_delete',
  893. 'translation_domain' => 'SonataAdminBundle',
  894. 'ask_confirmation' => true, // by default always true
  895. );
  896. }
  897. foreach ($this->getExtensions() as $extension) {
  898. // TODO: remove method check in next major release
  899. if (method_exists($extension, 'configureBatchActions')) {
  900. $actions = $extension->configureBatchActions($this, $actions);
  901. }
  902. }
  903. return $actions;
  904. }
  905. /**
  906. * {@inheritdoc}
  907. */
  908. public function getRoutes()
  909. {
  910. $this->buildRoutes();
  911. return $this->routes;
  912. }
  913. /**
  914. * {@inheritdoc}
  915. */
  916. public function getRouterIdParameter()
  917. {
  918. return $this->isChild() ? '{childId}' : '{id}';
  919. }
  920. /**
  921. * {@inheritdoc}
  922. */
  923. public function getIdParameter()
  924. {
  925. return $this->isChild() ? 'childId' : 'id';
  926. }
  927. /**
  928. * {@inheritdoc}
  929. */
  930. public function hasRoute($name)
  931. {
  932. if (!$this->routeGenerator) {
  933. throw new \RuntimeException('RouteGenerator cannot be null');
  934. }
  935. return $this->routeGenerator->hasAdminRoute($this, $name);
  936. }
  937. /**
  938. * {@inheritdoc}
  939. */
  940. public function isCurrentRoute($name, $adminCode = null)
  941. {
  942. if (!$this->hasRequest()) {
  943. return false;
  944. }
  945. $request = $this->getRequest();
  946. $route = $request->get('_route');
  947. if ($adminCode) {
  948. $admin = $this->getConfigurationPool()->getAdminByAdminCode($adminCode);
  949. } else {
  950. $admin = $this;
  951. }
  952. if (!$admin) {
  953. return false;
  954. }
  955. return ($admin->getBaseRouteName().'_'.$name) == $route;
  956. }
  957. /**
  958. * {@inheritdoc}
  959. */
  960. public function generateObjectUrl($name, $object, array $parameters = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
  961. {
  962. $parameters['id'] = $this->getUrlsafeIdentifier($object);
  963. return $this->generateUrl($name, $parameters, $absolute);
  964. }
  965. /**
  966. * {@inheritdoc}
  967. */
  968. public function generateUrl($name, array $parameters = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
  969. {
  970. return $this->routeGenerator->generateUrl($this, $name, $parameters, $absolute);
  971. }
  972. /**
  973. * {@inheritdoc}
  974. */
  975. public function generateMenuUrl($name, array $parameters = array(), $absolute = UrlGeneratorInterface::ABSOLUTE_PATH)
  976. {
  977. return $this->routeGenerator->generateMenuUrl($this, $name, $parameters, $absolute);
  978. }
  979. /**
  980. * @param array $templates
  981. */
  982. public function setTemplates(array $templates)
  983. {
  984. $this->templates = $templates;
  985. }
  986. /**
  987. * @param string $name
  988. * @param string $template
  989. */
  990. public function setTemplate($name, $template)
  991. {
  992. $this->templates[$name] = $template;
  993. }
  994. /**
  995. * @return array
  996. */
  997. public function getTemplates()
  998. {
  999. return $this->templates;
  1000. }
  1001. /**
  1002. * {@inheritdoc}
  1003. */
  1004. public function getTemplate($name)
  1005. {
  1006. if (isset($this->templates[$name])) {
  1007. return $this->templates[$name];
  1008. }
  1009. }
  1010. /**
  1011. * {@inheritdoc}
  1012. */
  1013. public function getNewInstance()
  1014. {
  1015. $object = $this->getModelManager()->getModelInstance($this->getClass());
  1016. foreach ($this->getExtensions() as $extension) {
  1017. $extension->alterNewInstance($this, $object);
  1018. }
  1019. return $object;
  1020. }
  1021. /**
  1022. * {@inheritdoc}
  1023. */
  1024. public function getFormBuilder()
  1025. {
  1026. $this->formOptions['data_class'] = $this->getClass();
  1027. $formBuilder = $this->getFormContractor()->getFormBuilder(
  1028. $this->getUniqid(),
  1029. $this->formOptions
  1030. );
  1031. $this->defineFormBuilder($formBuilder);
  1032. return $formBuilder;
  1033. }
  1034. /**
  1035. * This method is being called by the main admin class and the child class,
  1036. * the getFormBuilder is only call by the main admin class.
  1037. *
  1038. * @param FormBuilderInterface $formBuilder
  1039. */
  1040. public function defineFormBuilder(FormBuilderInterface $formBuilder)
  1041. {
  1042. $mapper = new FormMapper($this->getFormContractor(), $formBuilder, $this);
  1043. $this->configureFormFields($mapper);
  1044. foreach ($this->getExtensions() as $extension) {
  1045. $extension->configureFormFields($mapper);
  1046. }
  1047. $this->attachInlineValidator();
  1048. }
  1049. /**
  1050. * {@inheritdoc}
  1051. */
  1052. public function attachAdminClass(FieldDescriptionInterface $fieldDescription)
  1053. {
  1054. $pool = $this->getConfigurationPool();
  1055. $adminCode = $fieldDescription->getOption('admin_code');
  1056. if ($adminCode !== null) {
  1057. $admin = $pool->getAdminByAdminCode($adminCode);
  1058. } else {
  1059. $admin = $pool->getAdminByClass($fieldDescription->getTargetEntity());
  1060. }
  1061. if (!$admin) {
  1062. return;
  1063. }
  1064. if ($this->hasRequest()) {
  1065. $admin->setRequest($this->getRequest());
  1066. }
  1067. $fieldDescription->setAssociationAdmin($admin);
  1068. }
  1069. /**
  1070. * {@inheritdoc}
  1071. */
  1072. public function getObject($id)
  1073. {
  1074. $object = $this->getModelManager()->find($this->getClass(), $id);
  1075. foreach ($this->getExtensions() as $extension) {
  1076. $extension->alterObject($this, $object);
  1077. }
  1078. return $object;
  1079. }
  1080. /**
  1081. * {@inheritdoc}
  1082. */
  1083. public function getForm()
  1084. {
  1085. $this->buildForm();
  1086. return $this->form;
  1087. }
  1088. /**
  1089. * {@inheritdoc}
  1090. */
  1091. public function getList()
  1092. {
  1093. $this->buildList();
  1094. return $this->list;
  1095. }
  1096. /**
  1097. * {@inheritdoc}
  1098. */
  1099. public function createQuery($context = 'list')
  1100. {
  1101. $query = $this->getModelManager()->createQuery($this->class);
  1102. foreach ($this->extensions as $extension) {
  1103. $extension->configureQuery($this, $query, $context);
  1104. }
  1105. return $query;
  1106. }
  1107. /**
  1108. * {@inheritdoc}
  1109. */
  1110. public function getDatagrid()
  1111. {
  1112. $this->buildDatagrid();
  1113. return $this->datagrid;
  1114. }
  1115. /**
  1116. * {@inheritdoc}
  1117. */
  1118. public function buildTabMenu($action, AdminInterface $childAdmin = null)
  1119. {
  1120. if ($this->loaded['tab_menu']) {
  1121. return;
  1122. }
  1123. $this->loaded['tab_menu'] = true;
  1124. $menu = $this->menuFactory->createItem('root');
  1125. $menu->setChildrenAttribute('class', 'nav navbar-nav');
  1126. // Prevents BC break with KnpMenuBundle v1.x
  1127. if (method_exists($menu, 'setCurrentUri')) {
  1128. $menu->setCurrentUri($this->getRequest()->getBaseUrl().$this->getRequest()->getPathInfo());
  1129. }
  1130. $this->configureTabMenu($menu, $action, $childAdmin);
  1131. foreach ($this->getExtensions() as $extension) {
  1132. $extension->configureTabMenu($this, $menu, $action, $childAdmin);
  1133. }
  1134. $this->menu = $menu;
  1135. }
  1136. /**
  1137. * {@inheritdoc}
  1138. */
  1139. public function buildSideMenu($action, AdminInterface $childAdmin = null)
  1140. {
  1141. return $this->buildTabMenu($action, $childAdmin);
  1142. }
  1143. /**
  1144. * @param string $action
  1145. * @param AdminInterface $childAdmin
  1146. *
  1147. * @return ItemInterface
  1148. */
  1149. public function getSideMenu($action, AdminInterface $childAdmin = null)
  1150. {
  1151. if ($this->isChild()) {
  1152. return $this->getParent()->getSideMenu($action, $this);
  1153. }
  1154. $this->buildSideMenu($action, $childAdmin);
  1155. return $this->menu;
  1156. }
  1157. /**
  1158. * Returns the root code.
  1159. *
  1160. * @return string the root code
  1161. */
  1162. public function getRootCode()
  1163. {
  1164. return $this->getRoot()->getCode();
  1165. }
  1166. /**
  1167. * Returns the master admin.
  1168. *
  1169. * @return Admin the root admin class
  1170. */
  1171. public function getRoot()
  1172. {
  1173. $parentFieldDescription = $this->getParentFieldDescription();
  1174. if (!$parentFieldDescription) {
  1175. return $this;
  1176. }
  1177. return $parentFieldDescription->getAdmin()->getRoot();
  1178. }
  1179. /**
  1180. * {@inheritdoc}
  1181. */
  1182. public function setBaseControllerName($baseControllerName)
  1183. {
  1184. $this->baseControllerName = $baseControllerName;
  1185. }
  1186. /**
  1187. * {@inheritdoc}
  1188. */
  1189. public function getBaseControllerName()
  1190. {
  1191. return $this->baseControllerName;
  1192. }
  1193. /**
  1194. * @param string $label
  1195. */
  1196. public function setLabel($label)
  1197. {
  1198. $this->label = $label;
  1199. }
  1200. /**
  1201. * {@inheritdoc}
  1202. */
  1203. public function getLabel()
  1204. {
  1205. return $this->label;
  1206. }
  1207. /**
  1208. * @param bool $persist
  1209. */
  1210. public function setPersistFilters($persist)
  1211. {
  1212. $this->persistFilters = $persist;
  1213. }
  1214. /**
  1215. * @param int $maxPerPage
  1216. */
  1217. public function setMaxPerPage($maxPerPage)
  1218. {
  1219. $this->maxPerPage = $maxPerPage;
  1220. }
  1221. /**
  1222. * @return int
  1223. */
  1224. public function getMaxPerPage()
  1225. {
  1226. return $this->maxPerPage;
  1227. }
  1228. /**
  1229. * @param int $maxPageLinks
  1230. */
  1231. public function setMaxPageLinks($maxPageLinks)
  1232. {
  1233. $this->maxPageLinks = $maxPageLinks;
  1234. }
  1235. /**
  1236. * @return int
  1237. */
  1238. public function getMaxPageLinks()
  1239. {
  1240. return $this->maxPageLinks;
  1241. }
  1242. /**
  1243. * {@inheritdoc}
  1244. */
  1245. public function getFormGroups()
  1246. {
  1247. return $this->formGroups;
  1248. }
  1249. /**
  1250. * {@inheritdoc}
  1251. */
  1252. public function setFormGroups(array $formGroups)
  1253. {
  1254. $this->formGroups = $formGroups;
  1255. }
  1256. /**
  1257. * {@inheritdoc}
  1258. */
  1259. public function removeFieldFromFormGroup($key)
  1260. {
  1261. foreach ($this->formGroups as $name => $formGroup) {
  1262. unset($this->formGroups[$name]['fields'][$key]);
  1263. if (empty($this->formGroups[$name]['fields'])) {
  1264. unset($this->formGroups[$name]);
  1265. }
  1266. }
  1267. }
  1268. /**
  1269. * @param array $group
  1270. * @param array $keys
  1271. */
  1272. public function reorderFormGroup($group, array $keys)
  1273. {
  1274. $formGroups = $this->getFormGroups();
  1275. $formGroups[$group]['fields'] = array_merge(array_flip($keys), $formGroups[$group]['fields']);
  1276. $this->setFormGroups($formGroups);
  1277. }
  1278. /**
  1279. * {@inheritdoc}
  1280. */
  1281. public function getFormTabs()
  1282. {
  1283. return $this->formTabs;
  1284. }
  1285. /**
  1286. * {@inheritdoc}
  1287. */
  1288. public function setFormTabs(array $formTabs)
  1289. {
  1290. $this->formTabs = $formTabs;
  1291. }
  1292. /**
  1293. * {@inheritdoc}
  1294. */
  1295. public function getShowTabs()
  1296. {
  1297. return $this->showTabs;
  1298. }
  1299. /**
  1300. * {@inheritdoc}
  1301. */
  1302. public function setShowTabs(array $showTabs)
  1303. {
  1304. $this->showTabs = $showTabs;
  1305. }
  1306. /**
  1307. * {@inheritdoc}
  1308. */
  1309. public function getShowGroups()
  1310. {
  1311. return $this->showGroups;
  1312. }
  1313. /**
  1314. * {@inheritdoc}
  1315. */
  1316. public function setShowGroups(array $showGroups)
  1317. {
  1318. $this->showGroups = $showGroups;
  1319. }
  1320. /**
  1321. * {@inheritdoc}
  1322. */
  1323. public function reorderShowGroup($group, array $keys)
  1324. {
  1325. $showGroups = $this->getShowGroups();
  1326. $showGroups[$group]['fields'] = array_merge(array_flip($keys), $showGroups[$group]['fields']);
  1327. $this->setShowGroups($showGroups);
  1328. }
  1329. /**
  1330. * {@inheritdoc}
  1331. */
  1332. public function setParentFieldDescription(FieldDescriptionInterface $parentFieldDescription)
  1333. {
  1334. $this->parentFieldDescription = $parentFieldDescription;
  1335. }
  1336. /**
  1337. * {@inheritdoc}
  1338. */
  1339. public function getParentFieldDescription()
  1340. {
  1341. return $this->parentFieldDescription;
  1342. }
  1343. /**
  1344. * {@inheritdoc}
  1345. */
  1346. public function hasParentFieldDescription()
  1347. {
  1348. return $this->parentFieldDescription instanceof FieldDescriptionInterface;
  1349. }
  1350. /**
  1351. * {@inheritdoc}
  1352. */
  1353. public function setSubject($subject)
  1354. {
  1355. $this->subject = $subject;
  1356. }
  1357. /**
  1358. * {@inheritdoc}
  1359. */
  1360. public function getSubject()
  1361. {
  1362. if ($this->subject === null && $this->request) {
  1363. $id = $this->request->get($this->getIdParameter());
  1364. if (!preg_match('#^[0-9A-Fa-f\-]+$#', $id)) {
  1365. $this->subject = false;
  1366. } else {
  1367. $this->subject = $this->getModelManager()->find($this->class, $id);
  1368. }
  1369. }
  1370. return $this->subject;
  1371. }
  1372. /**
  1373. * {@inheritdoc}
  1374. */
  1375. public function hasSubject()
  1376. {
  1377. return $this->subject != null;
  1378. }
  1379. /**
  1380. * {@inheritdoc}
  1381. */
  1382. public function getFormFieldDescriptions()
  1383. {
  1384. $this->buildForm();
  1385. return $this->formFieldDescriptions;
  1386. }
  1387. /**
  1388. * {@inheritdoc}
  1389. */
  1390. public function getFormFieldDescription($name)
  1391. {
  1392. return $this->hasFormFieldDescription($name) ? $this->formFieldDescriptions[$name] : null;
  1393. }
  1394. /**
  1395. * Returns true if the admin has a FieldDescription with the given $name.
  1396. *
  1397. * @param string $name
  1398. *
  1399. * @return bool
  1400. */
  1401. public function hasFormFieldDescription($name)
  1402. {
  1403. return array_key_exists($name, $this->formFieldDescriptions) ? true : false;
  1404. }
  1405. /**
  1406. * {@inheritdoc}
  1407. */
  1408. public function addFormFieldDescription($name, FieldDescriptionInterface $fieldDescription)
  1409. {
  1410. $this->formFieldDescriptions[$name] = $fieldDescription;
  1411. }
  1412. /**
  1413. * remove a FieldDescription.
  1414. *
  1415. * @param string $name
  1416. */
  1417. public function removeFormFieldDescription($name)
  1418. {
  1419. unset($this->formFieldDescriptions[$name]);
  1420. }
  1421. /**
  1422. * build and return the collection of form FieldDescription.
  1423. *
  1424. * @return array collection of form FieldDescription
  1425. */
  1426. public function getShowFieldDescriptions()
  1427. {
  1428. $this->buildShow();
  1429. return $this->showFieldDescriptions;
  1430. }
  1431. /**
  1432. * Returns the form FieldDescription with the given $name.
  1433. *
  1434. * @param string $name
  1435. *
  1436. * @return FieldDescriptionInterface
  1437. */
  1438. public function getShowFieldDescription($name)
  1439. {
  1440. $this->buildShow();
  1441. return $this->hasShowFieldDescription($name) ? $this->showFieldDescriptions[$name] : null;
  1442. }
  1443. /**
  1444. * {@inheritdoc}
  1445. */
  1446. public function hasShowFieldDescription($name)
  1447. {
  1448. return array_key_exists($name, $this->showFieldDescriptions);
  1449. }
  1450. /**
  1451. * {@inheritdoc}
  1452. */
  1453. public function addShowFieldDescription($name, FieldDescriptionInterface $fieldDescription)
  1454. {
  1455. $this->showFieldDescriptions[$name] = $fieldDescription;
  1456. }
  1457. /**
  1458. * {@inheritdoc}
  1459. */
  1460. public function removeShowFieldDescription($name)
  1461. {
  1462. unset($this->showFieldDescriptions[$name]);
  1463. }
  1464. /**
  1465. * {@inheritdoc}
  1466. */
  1467. public function getListFieldDescriptions()
  1468. {
  1469. $this->buildList();
  1470. return $this->listFieldDescriptions;
  1471. }
  1472. /**
  1473. * {@inheritdoc}
  1474. */
  1475. public function getListFieldDescription($name)
  1476. {
  1477. return $this->hasListFieldDescription($name) ? $this->listFieldDescriptions[$name] : null;
  1478. }
  1479. /**
  1480. * {@inheritdoc}
  1481. */
  1482. public function hasListFieldDescription($name)
  1483. {
  1484. $this->buildList();
  1485. return array_key_exists($name, $this->listFieldDescriptions) ? true : false;
  1486. }
  1487. /**
  1488. * {@inheritdoc}
  1489. */
  1490. public function addListFieldDescription($name, FieldDescriptionInterface $fieldDescription)
  1491. {
  1492. $this->listFieldDescriptions[$name] = $fieldDescription;
  1493. }
  1494. /**
  1495. * {@inheritdoc}
  1496. */
  1497. public function removeListFieldDescription($name)
  1498. {
  1499. unset($this->listFieldDescriptions[$name]);
  1500. }
  1501. /**
  1502. * {@inheritdoc}
  1503. */
  1504. public function getFilterFieldDescription($name)
  1505. {
  1506. return $this->hasFilterFieldDescription($name) ? $this->filterFieldDescriptions[$name] : null;
  1507. }
  1508. /**
  1509. * {@inheritdoc}
  1510. */
  1511. public function hasFilterFieldDescription($name)
  1512. {
  1513. return array_key_exists($name, $this->filterFieldDescriptions) ? true : false;
  1514. }
  1515. /**
  1516. * {@inheritdoc}
  1517. */
  1518. public function addFilterFieldDescription($name, FieldDescriptionInterface $fieldDescription)
  1519. {
  1520. $this->filterFieldDescriptions[$name] = $fieldDescription;
  1521. }
  1522. /**
  1523. * {@inheritdoc}
  1524. */
  1525. public function removeFilterFieldDescription($name)
  1526. {
  1527. unset($this->filterFieldDescriptions[$name]);
  1528. }
  1529. /**
  1530. * {@inheritdoc}
  1531. */
  1532. public function getFilterFieldDescriptions()
  1533. {
  1534. $this->buildDatagrid();
  1535. return $this->filterFieldDescriptions;
  1536. }
  1537. /**
  1538. * {@inheritdoc}
  1539. */
  1540. public function addChild(AdminInterface $child)
  1541. {
  1542. $this->children[$child->getCode()] = $child;
  1543. $child->setBaseCodeRoute($this->getCode().'|'.$child->getCode());
  1544. $child->setParent($this);
  1545. }
  1546. /**
  1547. * {@inheritdoc}
  1548. */
  1549. public function hasChild($code)
  1550. {
  1551. return isset($this->children[$code]);
  1552. }
  1553. /**
  1554. * {@inheritdoc}
  1555. */
  1556. public function getChildren()
  1557. {
  1558. return $this->children;
  1559. }
  1560. /**
  1561. * {@inheritdoc}
  1562. */
  1563. public function getChild($code)
  1564. {
  1565. return $this->hasChild($code) ? $this->children[$code] : null;
  1566. }
  1567. /**
  1568. * {@inheritdoc}
  1569. */
  1570. public function setParent(AdminInterface $parent)
  1571. {
  1572. $this->parent = $parent;
  1573. }
  1574. /**
  1575. * {@inheritdoc}
  1576. */
  1577. public function getParent()
  1578. {
  1579. return $this->parent;
  1580. }
  1581. /**
  1582. * {@inheritdoc}
  1583. */
  1584. public function isChild()
  1585. {
  1586. return $this->parent instanceof AdminInterface;
  1587. }
  1588. /**
  1589. * Returns true if the admin has children, false otherwise.
  1590. *
  1591. * @return bool if the admin has children
  1592. */
  1593. public function hasChildren()
  1594. {
  1595. return count($this->children) > 0;
  1596. }
  1597. /**
  1598. * {@inheritdoc}
  1599. */
  1600. public function setUniqid($uniqid)
  1601. {
  1602. $this->uniqid = $uniqid;
  1603. }
  1604. /**
  1605. * {@inheritdoc}
  1606. */
  1607. public function getUniqid()
  1608. {
  1609. if (!$this->uniqid) {
  1610. $this->uniqid = 's'.uniqid();
  1611. }
  1612. return $this->uniqid;
  1613. }
  1614. /**
  1615. * Returns the classname label.
  1616. *
  1617. * @return string the classname label
  1618. */
  1619. public function getClassnameLabel()
  1620. {
  1621. return $this->classnameLabel;
  1622. }
  1623. /**
  1624. * {@inheritdoc}
  1625. */
  1626. public function getPersistentParameters()
  1627. {
  1628. $parameters = array();
  1629. foreach ($this->getExtensions() as $extension) {
  1630. $params = $extension->getPersistentParameters($this);
  1631. if (!is_array($params)) {
  1632. throw new \RuntimeException(sprintf('The %s::getPersistentParameters must return an array', get_class($extension)));
  1633. }
  1634. $parameters = array_merge($parameters, $params);
  1635. }
  1636. return $parameters;
  1637. }
  1638. /**
  1639. * @param string $name
  1640. *
  1641. * @return null|mixed
  1642. */
  1643. public function getPersistentParameter($name)
  1644. {
  1645. $parameters = $this->getPersistentParameters();
  1646. return isset($parameters[$name]) ? $parameters[$name] : null;
  1647. }
  1648. /**
  1649. * {@inheritdoc}
  1650. */
  1651. public function getBreadcrumbs($action)
  1652. {
  1653. if ($this->isChild()) {
  1654. return $this->getParent()->getBreadcrumbs($action);
  1655. }
  1656. $menu = $this->buildBreadcrumbs($action);
  1657. do {
  1658. $breadcrumbs[] = $menu;
  1659. } while ($menu = $menu->getParent());
  1660. $breadcrumbs = array_reverse($breadcrumbs);
  1661. array_shift($breadcrumbs);
  1662. return $breadcrumbs;
  1663. }
  1664. /**
  1665. * Generates the breadcrumbs array.
  1666. *
  1667. * Note: the method will be called by the top admin instance (parent => child)
  1668. *
  1669. * @param string $action
  1670. * @param ItemInterface|null $menu
  1671. *
  1672. * @return array
  1673. */
  1674. public function buildBreadcrumbs($action, MenuItemInterface $menu = null)
  1675. {
  1676. if (isset($this->breadcrumbs[$action])) {
  1677. return $this->breadcrumbs[$action];
  1678. }
  1679. if (!$menu) {
  1680. $menu = $this->menuFactory->createItem('root');
  1681. $menu = $menu->addChild(
  1682. $this->trans($this->getLabelTranslatorStrategy()->getLabel('dashboard', 'breadcrumb', 'link'), array(), 'SonataAdminBundle'),
  1683. array('uri' => $this->routeGenerator->generate('sonata_admin_dashboard'))
  1684. );
  1685. }
  1686. $menu = $menu->addChild(
  1687. $this->trans($this->getLabelTranslatorStrategy()->getLabel(sprintf('%s_list', $this->getClassnameLabel()), 'breadcrumb', 'link')),
  1688. array('uri' => $this->hasRoute('list') && $this->isGranted('LIST') ? $this->generateUrl('list') : null)
  1689. );
  1690. $childAdmin = $this->getCurrentChildAdmin();
  1691. if ($childAdmin) {
  1692. $id = $this->request->get($this->getIdParameter());
  1693. $menu = $menu->addChild(
  1694. $this->toString($this->getSubject()),
  1695. array('uri' => $this->hasRoute('edit') && $this->isGranted('EDIT') ? $this->generateUrl('edit', array('id' => $id)) : null)
  1696. );
  1697. return $childAdmin->buildBreadcrumbs($action, $menu);
  1698. }
  1699. if ($action === 'list' && $this->isChild()) {
  1700. $menu->setUri(false);
  1701. } elseif ($action !== 'create' && $this->hasSubject()) {
  1702. $menu = $menu->addChild($this->toString($this->getSubject()));
  1703. } else {
  1704. $menu = $menu->addChild(
  1705. $this->trans(
  1706. $this->getLabelTranslatorStrategy()->getLabel(
  1707. sprintf('%s_%s', $this->getClassnameLabel(), $action),
  1708. 'breadcrumb',
  1709. 'link'
  1710. )
  1711. )
  1712. );
  1713. }
  1714. return $this->breadcrumbs[$action] = $menu;
  1715. }
  1716. /**
  1717. * {@inheritdoc}
  1718. */
  1719. public function setCurrentChild($currentChild)
  1720. {
  1721. $this->currentChild = $currentChild;
  1722. }
  1723. /**
  1724. * {@inheritdoc}
  1725. */
  1726. public function getCurrentChild()
  1727. {
  1728. return $this->currentChild;
  1729. }
  1730. /**
  1731. * Returns the current child admin instance.
  1732. *
  1733. * @return AdminInterface|null the current child admin instance
  1734. */
  1735. public function getCurrentChildAdmin()
  1736. {
  1737. foreach ($this->children as $children) {
  1738. if ($children->getCurrentChild()) {
  1739. return $children;
  1740. }
  1741. }
  1742. return;
  1743. }
  1744. /**
  1745. * {@inheritdoc}
  1746. */
  1747. public function trans($id, array $parameters = array(), $domain = null, $locale = null)
  1748. {
  1749. $domain = $domain ?: $this->getTranslationDomain();
  1750. if (!$this->translator) {
  1751. return $id;
  1752. }
  1753. return $this->translator->trans($id, $parameters, $domain, $locale);
  1754. }
  1755. /**
  1756. * Translate a message id.
  1757. *
  1758. * @param string $id
  1759. * @param int $count
  1760. * @param array $parameters
  1761. * @param string|null $domain
  1762. * @param string|null $locale
  1763. *
  1764. * @return string the translated string
  1765. */
  1766. public function transChoice($id, $count, array $parameters = array(), $domain = null, $locale = null)
  1767. {
  1768. $domain = $domain ?: $this->getTranslationDomain();
  1769. if (!$this->translator) {
  1770. return $id;
  1771. }
  1772. return $this->translator->transChoice($id, $count, $parameters, $domain, $locale);
  1773. }
  1774. /**
  1775. * {@inheritdoc}
  1776. */
  1777. public function setTranslationDomain($translationDomain)
  1778. {
  1779. $this->translationDomain = $translationDomain;
  1780. }
  1781. /**
  1782. * {@inheritdoc}
  1783. */
  1784. public function getTranslationDomain()
  1785. {
  1786. return $this->translationDomain;
  1787. }
  1788. /**
  1789. * {@inheritdoc}
  1790. */
  1791. public function setTranslator(TranslatorInterface $translator)
  1792. {
  1793. $this->translator = $translator;
  1794. }
  1795. /**
  1796. * {@inheritdoc}
  1797. */
  1798. public function getTranslator()
  1799. {
  1800. return $this->translator;
  1801. }
  1802. /**
  1803. * {@inheritdoc}
  1804. */
  1805. public function getTranslationLabel($label, $context = '', $type = '')
  1806. {
  1807. return $this->getLabelTranslatorStrategy()->getLabel($label, $context, $type);
  1808. }
  1809. /**
  1810. * {@inheritdoc}
  1811. */
  1812. public function setRequest(Request $request)
  1813. {
  1814. $this->request = $request;
  1815. foreach ($this->getChildren() as $children) {
  1816. $children->setRequest($request);
  1817. }
  1818. }
  1819. /**
  1820. * {@inheritdoc}
  1821. */
  1822. public function getRequest()
  1823. {
  1824. if (!$this->request) {
  1825. throw new \RuntimeException('The Request object has not been set');
  1826. }
  1827. return $this->request;
  1828. }
  1829. /**
  1830. * {@inheritdoc}
  1831. */
  1832. public function hasRequest()
  1833. {
  1834. return $this->request !== null;
  1835. }
  1836. /**
  1837. * {@inheritdoc}
  1838. */
  1839. public function setFormContractor(FormContractorInterface $formBuilder)
  1840. {
  1841. $this->formContractor = $formBuilder;
  1842. }
  1843. /**
  1844. * @return FormContractorInterface
  1845. */
  1846. public function getFormContractor()
  1847. {
  1848. return $this->formContractor;
  1849. }
  1850. /**
  1851. * {@inheritdoc}
  1852. */
  1853. public function setDatagridBuilder(DatagridBuilderInterface $datagridBuilder)
  1854. {
  1855. $this->datagridBuilder = $datagridBuilder;
  1856. }
  1857. /**
  1858. * {@inheritdoc}
  1859. */
  1860. public function getDatagridBuilder()
  1861. {
  1862. return $this->datagridBuilder;
  1863. }
  1864. /**
  1865. * {@inheritdoc}
  1866. */
  1867. public function setListBuilder(ListBuilderInterface $listBuilder)
  1868. {
  1869. $this->listBuilder = $listBuilder;
  1870. }
  1871. /**
  1872. * {@inheritdoc}
  1873. */
  1874. public function getListBuilder()
  1875. {
  1876. return $this->listBuilder;
  1877. }
  1878. /**
  1879. * @param ShowBuilderInterface $showBuilder
  1880. */
  1881. public function setShowBuilder(ShowBuilderInterface $showBuilder)
  1882. {
  1883. $this->showBuilder = $showBuilder;
  1884. }
  1885. /**
  1886. * @return ShowBuilderInterface
  1887. */
  1888. public function getShowBuilder()
  1889. {
  1890. return $this->showBuilder;
  1891. }
  1892. /**
  1893. * {@inheritdoc}
  1894. */
  1895. public function setConfigurationPool(Pool $configurationPool)
  1896. {
  1897. $this->configurationPool = $configurationPool;
  1898. }
  1899. /**
  1900. * @return Pool
  1901. */
  1902. public function getConfigurationPool()
  1903. {
  1904. return $this->configurationPool;
  1905. }
  1906. /**
  1907. * {@inheritdoc}
  1908. */
  1909. public function setRouteGenerator(RouteGeneratorInterface $routeGenerator)
  1910. {
  1911. $this->routeGenerator = $routeGenerator;
  1912. }
  1913. /**
  1914. * @return RouteGeneratorInterface
  1915. */
  1916. public function getRouteGenerator()
  1917. {
  1918. return $this->routeGenerator;
  1919. }
  1920. /**
  1921. * {@inheritdoc}
  1922. */
  1923. public function getCode()
  1924. {
  1925. return $this->code;
  1926. }
  1927. /**
  1928. * @param string $baseCodeRoute
  1929. */
  1930. public function setBaseCodeRoute($baseCodeRoute)
  1931. {
  1932. $this->baseCodeRoute = $baseCodeRoute;
  1933. }
  1934. /**
  1935. * {@inheritdoc}
  1936. */
  1937. public function getBaseCodeRoute()
  1938. {
  1939. return $this->baseCodeRoute;
  1940. }
  1941. /**
  1942. * {@inheritdoc}
  1943. */
  1944. public function getModelManager()
  1945. {
  1946. return $this->modelManager;
  1947. }
  1948. /**
  1949. * @param ModelManagerInterface $modelManager
  1950. */
  1951. public function setModelManager(ModelManagerInterface $modelManager)
  1952. {
  1953. $this->modelManager = $modelManager;
  1954. }
  1955. /**
  1956. * {@inheritdoc}
  1957. */
  1958. public function getManagerType()
  1959. {
  1960. return $this->managerType;
  1961. }
  1962. /**
  1963. * @param string $type
  1964. */
  1965. public function setManagerType($type)
  1966. {
  1967. $this->managerType = $type;
  1968. }
  1969. /**
  1970. * {@inheritdoc}
  1971. */
  1972. public function getObjectIdentifier()
  1973. {
  1974. return $this->getCode();
  1975. }
  1976. /**
  1977. * Set the roles and permissions per role.
  1978. *
  1979. * @param array $information
  1980. */
  1981. public function setSecurityInformation(array $information)
  1982. {
  1983. $this->securityInformation = $information;
  1984. }
  1985. /**
  1986. * {@inheritdoc}
  1987. */
  1988. public function getSecurityInformation()
  1989. {
  1990. return $this->securityInformation;
  1991. }
  1992. /**
  1993. * Return the list of permissions the user should have in order to display the admin.
  1994. *
  1995. * @param string $context
  1996. *
  1997. * @return array
  1998. */
  1999. public function getPermissionsShow($context)
  2000. {
  2001. switch ($context) {
  2002. case self::CONTEXT_DASHBOARD:
  2003. case self::CONTEXT_MENU:
  2004. default:
  2005. return array('LIST');
  2006. }
  2007. }
  2008. /**
  2009. * {@inheritdoc}
  2010. */
  2011. public function showIn($context)
  2012. {
  2013. switch ($context) {
  2014. case self::CONTEXT_DASHBOARD:
  2015. case self::CONTEXT_MENU:
  2016. default:
  2017. return $this->isGranted($this->getPermissionsShow($context));
  2018. }
  2019. }
  2020. /**
  2021. * {@inheritdoc}
  2022. */
  2023. public function createObjectSecurity($object)
  2024. {
  2025. $this->getSecurityHandler()->createObjectSecurity($this, $object);
  2026. }
  2027. /**
  2028. * {@inheritdoc}
  2029. */
  2030. public function setSecurityHandler(SecurityHandlerInterface $securityHandler)
  2031. {
  2032. $this->securityHandler = $securityHandler;
  2033. }
  2034. /**
  2035. * {@inheritdoc}
  2036. */
  2037. public function getSecurityHandler()
  2038. {
  2039. return $this->securityHandler;
  2040. }
  2041. /**
  2042. * {@inheritdoc}
  2043. */
  2044. public function isGranted($name, $object = null)
  2045. {
  2046. $key = md5(json_encode($name).($object ? '/'.spl_object_hash($object) : ''));
  2047. if (!array_key_exists($key, $this->cacheIsGranted)) {
  2048. $this->cacheIsGranted[$key] = $this->securityHandler->isGranted($this, $name, $object ?: $this);
  2049. }
  2050. return $this->cacheIsGranted[$key];
  2051. }
  2052. /**
  2053. * {@inheritdoc}
  2054. */
  2055. public function getUrlsafeIdentifier($entity)
  2056. {
  2057. return $this->getModelManager()->getUrlsafeIdentifier($entity);
  2058. }
  2059. /**
  2060. * {@inheritdoc}
  2061. */
  2062. public function getNormalizedIdentifier($entity)
  2063. {
  2064. return $this->getModelManager()->getNormalizedIdentifier($entity);
  2065. }
  2066. /**
  2067. * {@inheritdoc}
  2068. */
  2069. public function id($entity)
  2070. {
  2071. return $this->getNormalizedIdentifier($entity);
  2072. }
  2073. /**
  2074. * {@inheritdoc}
  2075. */
  2076. public function setValidator($validator)
  2077. {
  2078. // TODO: Remove it when bumping requirements to SF 2.5+
  2079. if (!$validator instanceof ValidatorInterface && !$validator instanceof LegacyValidatorInterface) {
  2080. throw new \InvalidArgumentException('Argument 1 must be an instance of Symfony\Component\Validator\Validator\ValidatorInterface or Symfony\Component\Validator\ValidatorInterface');
  2081. }
  2082. $this->validator = $validator;
  2083. }
  2084. /**
  2085. * {@inheritdoc}
  2086. */
  2087. public function getValidator()
  2088. {
  2089. return $this->validator;
  2090. }
  2091. /**
  2092. * {@inheritdoc}
  2093. */
  2094. public function getShow()
  2095. {
  2096. $this->buildShow();
  2097. return $this->show;
  2098. }
  2099. /**
  2100. * {@inheritdoc}
  2101. */
  2102. public function setFormTheme(array $formTheme)
  2103. {
  2104. $this->formTheme = $formTheme;
  2105. }
  2106. /**
  2107. * {@inheritdoc}
  2108. */
  2109. public function getFormTheme()
  2110. {
  2111. return $this->formTheme;
  2112. }
  2113. /**
  2114. * {@inheritdoc}
  2115. */
  2116. public function setFilterTheme(array $filterTheme)
  2117. {
  2118. $this->filterTheme = $filterTheme;
  2119. }
  2120. /**
  2121. * {@inheritdoc}
  2122. */
  2123. public function getFilterTheme()
  2124. {
  2125. return $this->filterTheme;
  2126. }
  2127. /**
  2128. * {@inheritdoc}
  2129. */
  2130. public function addExtension(AdminExtensionInterface $extension)
  2131. {
  2132. $this->extensions[] = $extension;
  2133. }
  2134. /**
  2135. * {@inheritdoc}
  2136. */
  2137. public function getExtensions()
  2138. {
  2139. return $this->extensions;
  2140. }
  2141. /**
  2142. * {@inheritdoc}
  2143. */
  2144. public function setMenuFactory(MenuFactoryInterface $menuFactory)
  2145. {
  2146. $this->menuFactory = $menuFactory;
  2147. }
  2148. /**
  2149. * {@inheritdoc}
  2150. */
  2151. public function getMenuFactory()
  2152. {
  2153. return $this->menuFactory;
  2154. }
  2155. /**
  2156. * {@inheritdoc}
  2157. */
  2158. public function setRouteBuilder(RouteBuilderInterface $routeBuilder)
  2159. {
  2160. $this->routeBuilder = $routeBuilder;
  2161. }
  2162. /**
  2163. * {@inheritdoc}
  2164. */
  2165. public function getRouteBuilder()
  2166. {
  2167. return $this->routeBuilder;
  2168. }
  2169. /**
  2170. * {@inheritdoc}
  2171. */
  2172. public function toString($object)
  2173. {
  2174. if (!is_object($object)) {
  2175. return '';
  2176. }
  2177. if (method_exists($object, '__toString') && null !== $object->__toString()) {
  2178. return (string) $object;
  2179. }
  2180. return sprintf('%s:%s', ClassUtils::getClass($object), spl_object_hash($object));
  2181. }
  2182. /**
  2183. * {@inheritdoc}
  2184. */
  2185. public function setLabelTranslatorStrategy(LabelTranslatorStrategyInterface $labelTranslatorStrategy)
  2186. {
  2187. $this->labelTranslatorStrategy = $labelTranslatorStrategy;
  2188. }
  2189. /**
  2190. * {@inheritdoc}
  2191. */
  2192. public function getLabelTranslatorStrategy()
  2193. {
  2194. return $this->labelTranslatorStrategy;
  2195. }
  2196. /**
  2197. * {@inheritdoc}
  2198. */
  2199. public function supportsPreviewMode()
  2200. {
  2201. return $this->supportsPreviewMode;
  2202. }
  2203. /**
  2204. * Set custom per page options.
  2205. *
  2206. * @param array $options
  2207. */
  2208. public function setPerPageOptions(array $options)
  2209. {
  2210. $this->perPageOptions = $options;
  2211. }
  2212. /**
  2213. * Returns predefined per page options.
  2214. *
  2215. * @return array
  2216. */
  2217. public function getPerPageOptions()
  2218. {
  2219. return $this->perPageOptions;
  2220. }
  2221. /**
  2222. * Set pager type.
  2223. *
  2224. * @param string $pagerType
  2225. */
  2226. public function setPagerType($pagerType)
  2227. {
  2228. $this->pagerType = $pagerType;
  2229. }
  2230. /**
  2231. * Get pager type.
  2232. *
  2233. * @return string
  2234. */
  2235. public function getPagerType()
  2236. {
  2237. return $this->pagerType;
  2238. }
  2239. /**
  2240. * Returns true if the per page value is allowed, false otherwise.
  2241. *
  2242. * @param int $perPage
  2243. *
  2244. * @return bool
  2245. */
  2246. public function determinedPerPageValue($perPage)
  2247. {
  2248. return in_array($perPage, $this->perPageOptions);
  2249. }
  2250. /**
  2251. * {@inheritdoc}
  2252. */
  2253. public function isAclEnabled()
  2254. {
  2255. return $this->getSecurityHandler() instanceof AclSecurityHandlerInterface;
  2256. }
  2257. /**
  2258. * {@inheritdoc}
  2259. */
  2260. public function getObjectMetadata($object)
  2261. {
  2262. return new Metadata($this->toString($object));
  2263. }
  2264. /**
  2265. * {@inheritdoc}
  2266. */
  2267. public function getListModes()
  2268. {
  2269. return $this->listModes;
  2270. }
  2271. /**
  2272. * {@inheritdoc}
  2273. */
  2274. public function setListMode($mode)
  2275. {
  2276. if (!$this->hasRequest()) {
  2277. throw new \RuntimeException(sprintf('No request attached to the current admin: %s', $this->getCode()));
  2278. }
  2279. $this->getRequest()->getSession()->set(sprintf('%s.list_mode', $this->getCode()), $mode);
  2280. }
  2281. /**
  2282. * {@inheritdoc}
  2283. */
  2284. public function getListMode()
  2285. {
  2286. if (!$this->hasRequest()) {
  2287. return 'list';
  2288. }
  2289. return $this->getRequest()->getSession()->get(sprintf('%s.list_mode', $this->getCode()), 'list');
  2290. }
  2291. /**
  2292. * {@inheritdoc}
  2293. */
  2294. public function getAccessMapping()
  2295. {
  2296. return $this->accessMapping;
  2297. }
  2298. /**
  2299. * {@inheritdoc}
  2300. */
  2301. public function checkAccess($action, $object = null)
  2302. {
  2303. $access = $this->getAccess();
  2304. if (!array_key_exists($action, $access)) {
  2305. throw new \InvalidArgumentException(sprintf('Action "%s" could not be found in access mapping. Please make sure your action is defined into your admin class accessMapping property.', $action));
  2306. }
  2307. if (!is_array($access[$action])) {
  2308. $access[$action] = array($access[$action]);
  2309. }
  2310. foreach ($access[$action] as $role) {
  2311. if (false === $this->isGranted($role, $object)) {
  2312. throw new AccessDeniedException(sprintf('Access Denied to the action %s and role %s', $action, $role));
  2313. }
  2314. }
  2315. }
  2316. /**
  2317. * Hook to handle access authorization, without throw Exception.
  2318. *
  2319. * @param string $action
  2320. * @param object $object
  2321. *
  2322. * @return bool
  2323. */
  2324. public function hasAccess($action, $object = null)
  2325. {
  2326. $access = $this->getAccess();
  2327. if (!array_key_exists($action, $access)) {
  2328. return false;
  2329. }
  2330. if (!is_array($access[$action])) {
  2331. $access[$action] = array($access[$action]);
  2332. }
  2333. foreach ($access[$action] as $role) {
  2334. if (false === $this->isGranted($role, $object)) {
  2335. return false;
  2336. }
  2337. }
  2338. return true;
  2339. }
  2340. /**
  2341. * {@inheritdoc}
  2342. */
  2343. public function configureActionButtons($action, $object = null)
  2344. {
  2345. $list = array();
  2346. if (in_array($action, array('tree', 'show', 'edit', 'delete', 'list', 'batch'))) {
  2347. $list['create'] = array(
  2348. 'template' => 'SonataAdminBundle:Button:create_button.html.twig',
  2349. );
  2350. }
  2351. if (in_array($action, array('show', 'delete', 'acl', 'history')) && $object) {
  2352. $list['edit'] = array(
  2353. 'template' => 'SonataAdminBundle:Button:edit_button.html.twig',
  2354. );
  2355. }
  2356. if (in_array($action, array('show', 'edit', 'acl')) && $object) {
  2357. $list['history'] = array(
  2358. 'template' => 'SonataAdminBundle:Button:history_button.html.twig',
  2359. );
  2360. }
  2361. if (in_array($action, array('edit', 'history')) && $object) {
  2362. $list['acl'] = array(
  2363. 'template' => 'SonataAdminBundle:Button:acl_button.html.twig',
  2364. );
  2365. }
  2366. if (in_array($action, array('edit', 'history', 'acl')) && $object) {
  2367. $list['show'] = array(
  2368. 'template' => 'SonataAdminBundle:Button:show_button.html.twig',
  2369. );
  2370. }
  2371. if (in_array($action, array('show', 'edit', 'delete', 'acl', 'batch'))) {
  2372. $list['list'] = array(
  2373. 'template' => 'SonataAdminBundle:Button:list_button.html.twig',
  2374. );
  2375. }
  2376. return $list;
  2377. }
  2378. /**
  2379. * @param string $action
  2380. * @param mixed $object
  2381. *
  2382. * @return array
  2383. */
  2384. public function getActionButtons($action, $object = null)
  2385. {
  2386. $list = $this->configureActionButtons($action, $object);
  2387. foreach ($this->getExtensions() as $extension) {
  2388. // TODO: remove method check in next major release
  2389. if (method_exists($extension, 'configureActionButtons')) {
  2390. $list = $extension->configureActionButtons($this, $list, $action, $object);
  2391. }
  2392. }
  2393. return $list;
  2394. }
  2395. /**
  2396. * Get the list of actions that can be accessed directly from the dashboard.
  2397. *
  2398. * @return array
  2399. */
  2400. public function getDashboardActions()
  2401. {
  2402. $actions = array();
  2403. if ($this->hasRoute('create') && $this->isGranted('CREATE')) {
  2404. $actions['create'] = array(
  2405. 'label' => 'link_add',
  2406. 'translation_domain' => 'SonataAdminBundle',
  2407. 'template' => 'SonataAdminBundle:CRUD:dashboard__action_create.html.twig',
  2408. 'url' => $this->generateUrl('create'),
  2409. 'icon' => 'plus-circle',
  2410. );
  2411. }
  2412. if ($this->hasRoute('list') && $this->isGranted('LIST')) {
  2413. $actions['list'] = array(
  2414. 'label' => 'link_list',
  2415. 'translation_domain' => 'SonataAdminBundle',
  2416. 'url' => $this->generateUrl('list'),
  2417. 'icon' => 'list',
  2418. );
  2419. }
  2420. return $actions;
  2421. }
  2422. /**
  2423. * @param FormMapper $form
  2424. */
  2425. protected function configureFormFields(FormMapper $form)
  2426. {
  2427. }
  2428. /**
  2429. * @param ListMapper $list
  2430. */
  2431. protected function configureListFields(ListMapper $list)
  2432. {
  2433. }
  2434. /**
  2435. * @param DatagridMapper $filter
  2436. */
  2437. protected function configureDatagridFilters(DatagridMapper $filter)
  2438. {
  2439. }
  2440. /**
  2441. * @param ShowMapper $show
  2442. */
  2443. protected function configureShowFields(ShowMapper $show)
  2444. {
  2445. }
  2446. /**
  2447. * @param RouteCollection $collection
  2448. */
  2449. protected function configureRoutes(RouteCollection $collection)
  2450. {
  2451. }
  2452. /**
  2453. * DEPRECATED: Use configureTabMenu instead.
  2454. *
  2455. * @param MenuItemInterface $menu
  2456. * @param $action
  2457. * @param AdminInterface $childAdmin
  2458. *
  2459. * @return mixed
  2460. *
  2461. * @deprecated Use configureTabMenu instead
  2462. */
  2463. protected function configureSideMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  2464. {
  2465. }
  2466. /**
  2467. * Configures the tab menu in your admin.
  2468. *
  2469. * @param MenuItemInterface $menu
  2470. * @param string $action
  2471. * @param AdminInterface $childAdmin
  2472. *
  2473. * @return mixed
  2474. */
  2475. protected function configureTabMenu(MenuItemInterface $menu, $action, AdminInterface $childAdmin = null)
  2476. {
  2477. // Use configureSideMenu not to mess with previous overrides
  2478. // TODO remove once deprecation period is over
  2479. $this->configureSideMenu($menu, $action, $childAdmin);
  2480. }
  2481. /**
  2482. * build the view FieldDescription array.
  2483. */
  2484. protected function buildShow()
  2485. {
  2486. if ($this->show) {
  2487. return;
  2488. }
  2489. $this->show = new FieldDescriptionCollection();
  2490. $mapper = new ShowMapper($this->showBuilder, $this->show, $this);
  2491. $this->configureShowFields($mapper);
  2492. foreach ($this->getExtensions() as $extension) {
  2493. $extension->configureShowFields($mapper);
  2494. }
  2495. }
  2496. /**
  2497. * build the list FieldDescription array.
  2498. */
  2499. protected function buildList()
  2500. {
  2501. if ($this->list) {
  2502. return;
  2503. }
  2504. $this->list = $this->getListBuilder()->getBaseList();
  2505. $mapper = new ListMapper($this->getListBuilder(), $this->list, $this);
  2506. if (count($this->getBatchActions()) > 0) {
  2507. $fieldDescription = $this->getModelManager()->getNewFieldDescriptionInstance($this->getClass(), 'batch', array(
  2508. 'label' => 'batch',
  2509. 'code' => '_batch',
  2510. 'sortable' => false,
  2511. 'virtual_field' => true,
  2512. ));
  2513. $fieldDescription->setAdmin($this);
  2514. $fieldDescription->setTemplate($this->getTemplate('batch'));
  2515. $mapper->add($fieldDescription, 'batch');
  2516. }
  2517. $this->configureListFields($mapper);
  2518. foreach ($this->getExtensions() as $extension) {
  2519. $extension->configureListFields($mapper);
  2520. }
  2521. if ($this->hasRequest() && $this->getRequest()->isXmlHttpRequest()) {
  2522. $fieldDescription = $this->getModelManager()->getNewFieldDescriptionInstance($this->getClass(), 'select', array(
  2523. 'label' => false,
  2524. 'code' => '_select',
  2525. 'sortable' => false,
  2526. 'virtual_field' => false,
  2527. ));
  2528. $fieldDescription->setAdmin($this);
  2529. $fieldDescription->setTemplate($this->getTemplate('select'));
  2530. $mapper->add($fieldDescription, 'select');
  2531. }
  2532. }
  2533. /**
  2534. * Build the form FieldDescription collection.
  2535. */
  2536. protected function buildForm()
  2537. {
  2538. if ($this->form) {
  2539. return;
  2540. }
  2541. // append parent object if any
  2542. // todo : clean the way the Admin class can retrieve set the object
  2543. if ($this->isChild() && $this->getParentAssociationMapping()) {
  2544. $parent = $this->getParent()->getObject($this->request->get($this->getParent()->getIdParameter()));
  2545. $propertyAccessor = $this->getConfigurationPool()->getPropertyAccessor();
  2546. $propertyPath = new PropertyPath($this->getParentAssociationMapping());
  2547. $object = $this->getSubject();
  2548. $value = $propertyAccessor->getValue($object, $propertyPath);
  2549. if (is_array($value) || ($value instanceof \Traversable && $value instanceof \ArrayAccess)) {
  2550. $value[] = $parent;
  2551. $propertyAccessor->setValue($object, $propertyPath, $value);
  2552. } else {
  2553. $propertyAccessor->setValue($object, $propertyPath, $parent);
  2554. }
  2555. }
  2556. $this->form = $this->getFormBuilder()->getForm();
  2557. }
  2558. /**
  2559. * Gets the subclass corresponding to the given name.
  2560. *
  2561. * @param string $name The name of the sub class
  2562. *
  2563. * @return string the subclass
  2564. */
  2565. protected function getSubClass($name)
  2566. {
  2567. if ($this->hasSubClass($name)) {
  2568. return $this->subClasses[$name];
  2569. }
  2570. throw new \RuntimeException(sprintf('Unable to find the subclass `%s` for admin `%s`', $name, get_class($this)));
  2571. }
  2572. /**
  2573. * Attach the inline validator to the model metadata, this must be done once per admin.
  2574. */
  2575. protected function attachInlineValidator()
  2576. {
  2577. $admin = $this;
  2578. // add the custom inline validation option
  2579. // TODO: Remove conditional method when bumping requirements to SF 2.5+
  2580. if (method_exists($this->validator, 'getMetadataFor')) {
  2581. $metadata = $this->validator->getMetadataFor($this->getClass());
  2582. } else {
  2583. $metadata = $this->validator->getMetadataFactory()->getMetadataFor($this->getClass());
  2584. }
  2585. $metadata->addConstraint(new InlineConstraint(array(
  2586. 'service' => $this,
  2587. 'method' => function (ErrorElement $errorElement, $object) use ($admin) {
  2588. /* @var \Sonata\AdminBundle\Admin\AdminInterface $admin */
  2589. // This avoid the main validation to be cascaded to children
  2590. // The problem occurs when a model Page has a collection of Page as property
  2591. if ($admin->hasSubject() && spl_object_hash($object) !== spl_object_hash($admin->getSubject())) {
  2592. return;
  2593. }
  2594. $admin->validate($errorElement, $object);
  2595. foreach ($admin->getExtensions() as $extension) {
  2596. $extension->validate($admin, $errorElement, $object);
  2597. }
  2598. },
  2599. 'serializingWarning' => true,
  2600. )));
  2601. }
  2602. /**
  2603. * Predefine per page options.
  2604. */
  2605. protected function predefinePerPageOptions()
  2606. {
  2607. array_unshift($this->perPageOptions, $this->maxPerPage);
  2608. $this->perPageOptions = array_unique($this->perPageOptions);
  2609. sort($this->perPageOptions);
  2610. }
  2611. /**
  2612. * Return list routes with permissions name.
  2613. *
  2614. * @return array
  2615. */
  2616. protected function getAccess()
  2617. {
  2618. $access = array_merge(array(
  2619. 'acl' => 'MASTER',
  2620. 'export' => 'EXPORT',
  2621. 'historyCompareRevisions' => 'EDIT',
  2622. 'historyViewRevision' => 'EDIT',
  2623. 'history' => 'EDIT',
  2624. 'edit' => 'EDIT',
  2625. 'show' => 'VIEW',
  2626. 'create' => 'CREATE',
  2627. 'delete' => 'DELETE',
  2628. 'batchDelete' => 'DELETE',
  2629. 'list' => 'LIST',
  2630. ), $this->getAccessMapping());
  2631. foreach ($this->extensions as $extension) {
  2632. // TODO: remove method check in next major release
  2633. if (method_exists($extension, 'getAccessMapping')) {
  2634. $access = array_merge($access, $extension->getAccessMapping($this));
  2635. }
  2636. }
  2637. return $access;
  2638. }
  2639. /**
  2640. * Build all the related urls to the current admin.
  2641. */
  2642. private function buildRoutes()
  2643. {
  2644. if ($this->loaded['routes']) {
  2645. return;
  2646. }
  2647. $this->loaded['routes'] = true;
  2648. $this->routes = new RouteCollection(
  2649. $this->getBaseCodeRoute(),
  2650. $this->getBaseRouteName(),
  2651. $this->getBaseRoutePattern(),
  2652. $this->getBaseControllerName()
  2653. );
  2654. $this->routeBuilder->build($this, $this->routes);
  2655. $this->configureRoutes($this->routes);
  2656. foreach ($this->getExtensions() as $extension) {
  2657. $extension->configureRoutes($this, $this->routes);
  2658. }
  2659. }
  2660. }