PageRenderTime 46ms CodeModel.GetById 19ms RepoModel.GetById 0ms app.codeStats 0ms

/plugins/Content/src/Controller/Admin/ManageController.php

http://github.com/QuickAppsCMS/QuickApps-CMS
PHP | 375 lines | 250 code | 44 blank | 81 comment | 39 complexity | 4fff145eb61ad009a74732e42c299118 MD5 | raw file
Possible License(s): LGPL-2.1, MPL-2.0-no-copyleft-exception, GPL-3.0
  1. <?php
  2. /**
  3. * Licensed under The GPL-3.0 License
  4. * For full copyright and license information, please see the LICENSE.txt
  5. * Redistributions of files must retain the above copyright notice.
  6. *
  7. * @since 2.0.0
  8. * @author Christopher Castro <chris@quickapps.es>
  9. * @link http://www.quickappscms.org
  10. * @license http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
  11. */
  12. namespace Content\Controller\Admin;
  13. use Cake\ORM\Query;
  14. use Content\Controller\AppController;
  15. use Content\Error\ContentCreateException;
  16. use Content\Error\ContentDeleteException;
  17. use Content\Error\ContentEditException;
  18. use Content\Error\ContentNotFoundException;
  19. use Content\Error\ContentTranslateException;
  20. use Content\Error\ContentTypeNotFoundException;
  21. use Locale\Utility\LocaleToolbox;
  22. /**
  23. * Content manager controller.
  24. *
  25. * Provides full CRUD for contents.
  26. *
  27. * @property \Content\Model\Table\ContentsTable $Contents
  28. * @property \Content\Model\Table\ContentTypesTable $ContentTypes
  29. * @property \Content\Model\Table\ContentRevisionsTable $ContentRevisions
  30. */
  31. class ManageController extends AppController
  32. {
  33. /**
  34. * An array containing the names of helpers controllers uses.
  35. *
  36. * @var array
  37. */
  38. public $helpers = ['Paginator'];
  39. /**
  40. * Shows a list of all the contents.
  41. *
  42. * @return void
  43. */
  44. public function index()
  45. {
  46. $this->loadModel('Content.Contents');
  47. $this->Contents->CreatedBy->fieldable(false);
  48. $this->Contents->ModifiedBy->fieldable(false);
  49. $contents = $this->Contents
  50. ->find('all', ['fieldable' => false])
  51. ->contain(['ContentTypes', 'CreatedBy', 'ModifiedBy']);
  52. if (!empty($this->request->query['filter']) &&
  53. $contents instanceof Query
  54. ) {
  55. $this->Contents->search($this->request->query['filter'], $contents);
  56. }
  57. $this->title(__d('content', 'Contents List'));
  58. $this->set('contents', $this->paginate($contents));
  59. $this->Breadcrumb->push('/admin/content/manage');
  60. }
  61. /**
  62. * Content-type selection screen.
  63. *
  64. * User must select which content type wish to create.
  65. *
  66. * @return void
  67. */
  68. public function create()
  69. {
  70. $this->loadModel('Content.ContentTypes');
  71. $types = $this->ContentTypes->find()
  72. ->select(['id', 'slug', 'name', 'description'])
  73. ->all();
  74. $this->title(__d('content', 'Create New Content'));
  75. $this->set('types', $types);
  76. $this->Breadcrumb
  77. ->push('/admin/content/manage')
  78. ->push(__d('content', 'Create new content'), '');
  79. }
  80. /**
  81. * Shows the "new content" form.
  82. *
  83. * @param string $typeSlug Content type slug. e.g.: "article", "product-info"
  84. * @return void
  85. * @throws \Content\Error\ContentTypeNotFoundException When content type was not
  86. * found
  87. * @throws \Content\Error\ContentCreateException When current user is not allowed
  88. * to create contents of this type
  89. */
  90. public function add($typeSlug)
  91. {
  92. $this->loadModel('Content.ContentTypes');
  93. $this->loadModel('Content.Contents');
  94. $this->Contents->unbindComments();
  95. $type = $this->ContentTypes->find()
  96. ->where(['slug' => $typeSlug])
  97. ->limit(1)
  98. ->first();
  99. if (!$type) {
  100. throw new ContentTypeNotFoundException(__d('content', 'The specified content type ({0}) does not exists.', $type));
  101. }
  102. if (!$type->userAllowed('create')) {
  103. throw new ContentCreateException(__d('content', 'You are not allowed to create contents of this type ({0}).', $type->name));
  104. }
  105. if ($this->request->data()) {
  106. $data = $this->request->data();
  107. $data['content_type_slug'] = $type->slug;
  108. $data['content_type_id'] = $type->id;
  109. $content = $this->Contents->newEntity($data);
  110. if ($this->Contents->save($content)) {
  111. if (!$type->userAllowed('publish')) {
  112. $this->Flash->warning(__d('content', 'Content created, but awaiting moderation before publishing it.'));
  113. } else {
  114. $this->Flash->success(__d('content', 'Content created!.'));
  115. }
  116. $this->redirect(['plugin' => 'Content', 'controller' => 'manage', 'action' => 'edit', 'prefix' => 'admin', $content->id]);
  117. } else {
  118. $this->Flash->danger(__d('content', 'Something went wrong, please check your information.'));
  119. }
  120. } else {
  121. $content = $this->Contents->newEntity(['content_type_slug' => $type->slug]);
  122. $content->setDefaults($type);
  123. }
  124. $content->set('content_type', $type);
  125. $content = $this->Contents->attachFields($content);
  126. $languages = LocaleToolbox::languagesList();
  127. $roles = $this->Contents->Roles->find('list');
  128. $this->title(__d('content', 'Create New Content <small>({0})</small>', $type->slug));
  129. $this->set(compact('content', 'type', 'languages', 'roles'));
  130. $this->Breadcrumb
  131. ->push('/admin/content/manage')
  132. ->push(__d('content', 'Create new content'), ['plugin' => 'Content', 'controller' => 'manage', 'action' => 'create'])
  133. ->push($type->name, '');
  134. }
  135. /**
  136. * Edit form for the given content.
  137. *
  138. * @param int $id Content's ID
  139. * @param false|int $revisionId Fill form with content's revision information
  140. * @return void
  141. * @throws \Content\Error\ContentNotFoundException When content type, or when
  142. * content content was not found
  143. * @throws \Content\Error\ContentEditException When user is not allowed to edit
  144. * contents of this type
  145. */
  146. public function edit($id, $revisionId = false)
  147. {
  148. $this->loadModel('Content.Contents');
  149. $this->Contents->unbindComments();
  150. $content = false;
  151. if (intval($revisionId) > 0 && !$this->request->data()) {
  152. $this->loadModel('Content.ContentRevisions');
  153. $revision = $this->ContentRevisions->find()
  154. ->where(['id' => $revisionId, 'content_id' => $id])
  155. ->first();
  156. if ($revision) {
  157. $content = $revision->data;
  158. if (!empty($content->_fields)) {
  159. // Merge previous data for each field, we just load the data (metadata keeps to the latests configured).
  160. $_fieldsRevision = $content->_fields;
  161. $content = $this->Contents->attachFields($content);
  162. $content->_fields = $content->_fields->map(function ($field, $key) use ($_fieldsRevision) {
  163. $fieldRevision = $_fieldsRevision[$field->name];
  164. if ($fieldRevision) {
  165. $field->set('value', $fieldRevision->value);
  166. $field->set('extra', $fieldRevision->extra);
  167. }
  168. return $field;
  169. });
  170. }
  171. }
  172. } else {
  173. $content = $this->Contents
  174. ->find()
  175. ->where(['Contents.id' => $id])
  176. ->contain([
  177. 'Roles',
  178. 'Translations',
  179. 'ContentRevisions',
  180. 'ContentTypes',
  181. 'TranslationOf',
  182. ])
  183. ->first();
  184. }
  185. if (!$content || empty($content->content_type)) {
  186. throw new ContentNotFoundException(__d('content', 'The requested page was not found.'));
  187. }
  188. if (!$content->content_type->userAllowed('edit')) {
  189. throw new ContentEditException(__d('content', 'You are not allowed to create contents of this type ({0}).', $content->content_type->name));
  190. }
  191. if (!empty($this->request->data)) {
  192. if (empty($this->request->data['regenerate_slug'])) {
  193. $this->Contents->behaviors()->Sluggable->config(['on' => 'create']);
  194. } else {
  195. unset($this->request->data['regenerate_slug']);
  196. }
  197. $content->accessible([
  198. 'id',
  199. 'content_type_id',
  200. 'content_type_slug',
  201. 'translation_for',
  202. 'created_by',
  203. ], false);
  204. $content = $this->Contents->patchEntity($content, $this->request->data());
  205. if ($this->Contents->save($content, ['atomic' => true, 'associated' => ['Roles']])) {
  206. $this->Flash->success(__d('content', 'Content updated!'));
  207. $this->redirect("/admin/content/manage/edit/{$id}");
  208. } else {
  209. $this->Flash->danger(__d('content', 'Something went wrong, please check your information.'));
  210. }
  211. }
  212. $languages = LocaleToolbox::languagesList();
  213. $roles = $this->Contents->Roles->find('list');
  214. $this->title(__d('content', 'Editing Content: {0} <small>({1})</small>', $content->title, $content->content_type_slug));
  215. $this->set(compact('content', 'languages', 'roles'));
  216. $this->Breadcrumb
  217. ->push('/admin/content/manage/index')
  218. ->push(__d('content', 'Editing content'), '#');
  219. }
  220. /**
  221. * Translate the given content to a different language.
  222. *
  223. * @param int $contentId Content's ID
  224. * @return void
  225. * @throws \Content\Error\ContentNotFoundException When content type, or when
  226. * content content was not found
  227. * @throws \Content\Error\ContentTranslateException When user is not allowed to
  228. * translate contents of this type
  229. */
  230. public function translate($contentId)
  231. {
  232. $this->loadModel('Content.Contents');
  233. $content = $this->Contents->get($contentId, ['contain' => 'ContentTypes']);
  234. if (!$content || empty($content->content_type)) {
  235. throw new ContentNotFoundException(__d('content', 'The requested page was not found.'));
  236. }
  237. if (!$content->content_type->userAllowed('translate')) {
  238. throw new ContentTranslateException(__d('content', 'You are not allowed to translate contents of this type ({0}).', $content->content_type->name));
  239. }
  240. if (!$content->language || $content->translation_for) {
  241. $this->Flash->danger(__d('content', 'You cannot translate this content.'));
  242. $this->redirect(['plugin' => 'Content', 'controller' => 'manage', 'action' => 'index']);
  243. }
  244. $translations = $this->Contents
  245. ->find()
  246. ->where(['translation_for' => $content->id])
  247. ->all();
  248. $languages = LocaleToolbox::languagesList();
  249. $illegal = array_merge([$content->language], $translations->extract('language')->toArray());
  250. foreach ($languages as $code => $name) {
  251. if (in_array($code, $illegal)) {
  252. unset($languages[$code]);
  253. }
  254. }
  255. if (!empty($languages) &&
  256. !empty($this->request->data['language']) &&
  257. !empty($this->request->data['title']) &&
  258. $this->request->data['language'] !== $content->language
  259. ) {
  260. $this->Contents->fieldable(false); // fix, wont trigger fields validation
  261. $newContent = $this->Contents->newEntity([
  262. 'content_type_id' => $content->get('content_type_id'),
  263. 'content_type_slug' => $content->get('content_type_slug'),
  264. 'title' => $content->get('title'),
  265. 'status' => false,
  266. 'title' => $this->request->data['title'],
  267. 'translation_for' => $content->id,
  268. 'language' => $this->request->data['language'],
  269. ]);
  270. if ($this->Contents->save($newContent)) {
  271. $this->Flash->success(__d('content', 'Translation successfully created and was marked as unpublished. Complete the translation before publishing.'));
  272. $this->redirect(['plugin' => 'Content', 'controller' => 'manage', 'action' => 'edit', $newContent->id]);
  273. } else {
  274. $this->Flash->set(__d('content', 'Translation could not be created'), [
  275. 'element' => 'System.installer_errors',
  276. 'params' => ['errors' => $newContent->errors()],
  277. ]);
  278. }
  279. }
  280. $this->title(__d('content', 'Translate Content'));
  281. $this->set(compact('content', 'translations', 'languages'));
  282. $this->Breadcrumb
  283. ->push('/admin/content/manage')
  284. ->push(__d('content', 'Translating content'), '');
  285. }
  286. /**
  287. * Deletes the given content by ID.
  288. *
  289. * @param int $contentId Content's ID
  290. * @return void
  291. */
  292. public function delete($contentId)
  293. {
  294. $this->loadModel('Content.Contents');
  295. $content = $this->Contents->get($contentId, ['contain' => ['ContentTypes']]);
  296. if (!$content || empty($content->content_type)) {
  297. throw new ContentNotFoundException(__d('content', 'The requested page was not found.'));
  298. }
  299. if (!$content->content_type->userAllowed('translate')) {
  300. throw new ContentDeleteException(__d('content', 'You are not allowed to delete contents of this type ({0}).', $content->content_type->name));
  301. }
  302. if ($this->Contents->delete($content, ['atomic' => true])) {
  303. $this->Flash->success(__d('content', 'Content was successfully removed!'));
  304. } else {
  305. $this->Flash->danger(__d('content', 'Unable to remove this content, please try again.'));
  306. }
  307. $this->title(__d('content', 'Delete Content'));
  308. $this->redirect($this->referer());
  309. }
  310. /**
  311. * Removes the given revision of the given content.
  312. *
  313. * @param int $contentId Content's ID
  314. * @param int $revisionId Revision's ID
  315. * @return void Redirects to previous page
  316. */
  317. public function deleteRevision($contentId, $revisionId)
  318. {
  319. $this->loadModel('Content.ContentRevisions');
  320. $revision = $this->ContentRevisions->find()
  321. ->where(['id' => $revisionId, 'content_id' => $contentId])
  322. ->first();
  323. if ($this->ContentRevisions->delete($revision, ['atomic' => true])) {
  324. $this->Flash->success(__d('content', 'Revision was successfully removed!'));
  325. } else {
  326. $this->Flash->danger(__d('content', 'Unable to remove this revision, please try again.'));
  327. }
  328. $this->title(__d('content', 'Editing Content Revision'));
  329. $this->redirect($this->referer());
  330. }
  331. }