1 <?php
  2 
  3 /**
  4  * @package redaxo\structure\content
  5  */
  6 class rex_content_service
  7 {
  8     /**
  9      * Verschiebt einen Slice.
 10      *
 11      * @param int    $slice_id  Id des Slices
 12      * @param int    $clang     Id der Sprache
 13      * @param string $direction Richtung in die verschoben werden soll
 14      *
 15      * @throws rex_exception
 16      * @throws rex_api_exception
 17      *
 18      * @return string Eine Statusmeldung
 19      */
 20     public static function moveSlice($slice_id, $clang, $direction)
 21     {
 22         // ctype beachten
 23         // verschieben / vertauschen
 24         // article regenerieren.
 25 
 26         // check if slice id is valid
 27         $CM = rex_sql::factory();
 28         $CM->setQuery('select * from ' . rex::getTablePrefix() . 'article_slice where id=? and clang_id=?', [$slice_id, $clang]);
 29         if ($CM->getRows() == 1) {
 30             // origin value for later success-check
 31             $oldPriority = $CM->getValue('priority');
 32 
 33             // prepare sql for later saving
 34             $upd = rex_sql::factory();
 35             $upd->setTable(rex::getTablePrefix() . 'article_slice');
 36             $upd->setWhere([
 37                 'id' => $slice_id,
 38             ]);
 39 
 40             // some vars for later use
 41             $article_id = $CM->getValue('article_id');
 42             $ctype = $CM->getValue('ctype_id');
 43             $slice_revision = $CM->getValue('revision');
 44 
 45             rex_extension::registerPoint(new rex_extension_point('SLICE_MOVE', '', [
 46                 'direction' => $direction,
 47                 'slice_id' => $slice_id,
 48                 'article_id' => $article_id,
 49                 'clang_id' => $clang,
 50                 'slice_revision' => $slice_revision,
 51             ]));
 52 
 53             if ($direction == 'moveup' || $direction == 'movedown') {
 54                 if ($direction == 'moveup') {
 55                     $upd->setValue('priority', $CM->getValue('priority') - 1);
 56                     $updSort = 'DESC';
 57                 } else {
 58                     $upd->setValue('priority', $CM->getValue('priority') + 1);
 59                     $updSort = 'ASC';
 60                 }
 61                 $upd->addGlobalUpdateFields(self::getUser());
 62                 $upd->update();
 63 
 64                 rex_sql_util::organizePriorities(
 65                     rex::getTable('article_slice'),
 66                     'priority',
 67                     'article_id=' . (int) $article_id . ' AND clang_id=' . (int) $clang . ' AND ctype_id=' . (int) $ctype . ' AND revision=' . (int) $slice_revision,
 68                     'priority, updatedate ' . $updSort
 69                 );
 70 
 71                 // check if the slice moved at all (first cannot be moved up, last not down)
 72                 $CM->setQuery('select * from ' . rex::getTablePrefix() . 'article_slice where id=? and clang_id=?', [$slice_id, $clang]);
 73                 $newPriority = $CM->getValue('priority');
 74                 if ($oldPriority == $newPriority) {
 75                     throw new rex_api_exception(rex_i18n::msg('slice_moved_error'));
 76                 }
 77 
 78                 rex_article_cache::deleteContent($article_id, $clang);
 79             } else {
 80                 throw new rex_exception('rex_moveSlice: Unsupported direction "' . $direction . '"!');
 81             }
 82         } else {
 83             throw new rex_api_exception(rex_i18n::msg('slice_moved_error'));
 84         }
 85 
 86         return rex_i18n::msg('slice_moved');
 87     }
 88 
 89     /**
 90      * Löscht einen Slice.
 91      *
 92      * @param int $slice_id Id des Slices
 93      *
 94      * @return bool TRUE bei Erfolg, sonst FALSE
 95      */
 96     public static function deleteSlice($slice_id)
 97     {
 98         // check if slice id is valid
 99         $curr = rex_sql::factory();
100         $curr->setQuery('SELECT * FROM ' . rex::getTablePrefix() . 'article_slice WHERE id=?', [$slice_id]);
101         if ($curr->getRows() != 1) {
102             return false;
103         }
104 
105         rex_extension::registerPoint(new rex_extension_point('SLICE_DELETE', '', [
106             'slice_id' => $slice_id,
107             'article_id' => $curr->getValue('article_id'),
108             'clang_id' => $curr->getValue('clang_id'),
109             'slice_revision' => $curr->getValue('revision'),
110         ]));
111 
112         // delete the slice
113         $del = rex_sql::factory();
114         $del->setQuery('DELETE FROM ' . rex::getTablePrefix() . 'article_slice WHERE id=?', [$slice_id]);
115 
116         // reorg remaining slices
117         rex_sql_util::organizePriorities(
118             rex::getTable('article_slice'),
119             'priority',
120             'article_id=' . $curr->getValue('article_id') . ' AND clang_id=' . $curr->getValue('clang_id') . ' AND ctype_id=' . $curr->getValue('ctype_id') . ' AND revision=' . $curr->getValue('revision'),
121             'priority'
122         );
123 
124         // check if delete was successfull
125         return $curr->getRows() == 1;
126     }
127 
128     /**
129      * Kopiert die Inhalte eines Artikels in einen anderen Artikel.
130      *
131      * @param int $from_id    ArtikelId des Artikels, aus dem kopiert werden (Quell ArtikelId)
132      * @param int $to_id      ArtikelId des Artikel, in den kopiert werden sollen (Ziel ArtikelId)
133      * @param int $from_clang ClangId des Artikels, aus dem kopiert werden soll (Quell ClangId)
134      * @param int $to_clang   ClangId des Artikels, in den kopiert werden soll (Ziel ClangId)
135      * @param int $revision
136      *
137      * @return bool TRUE bei Erfolg, sonst FALSE
138      */
139     public static function copyContent($from_id, $to_id, $from_clang = 1, $to_clang = 1, $revision = 0)
140     {
141         if ($from_id == $to_id && $from_clang == $to_clang) {
142             return false;
143         }
144 
145         $gc = rex_sql::factory();
146         $gc->setQuery('select * from ' . rex::getTablePrefix() . 'article_slice where article_id=? and clang_id=? and revision=?', [$from_id, $from_clang, $revision]);
147 
148         if (!$gc->getRows()) {
149             return true;
150         }
151 
152         rex_extension::registerPoint(new rex_extension_point('ART_SLICES_COPY', '', [
153             'article_id' => $to_id,
154             'clang_id' => $to_clang,
155             'slice_revision' => $revision,
156         ]));
157 
158         $ins = rex_sql::factory();
159         //$ins->setDebug();
160         $ctypes = [];
161 
162         $cols = rex_sql::factory();
163         //$cols->setDebug();
164         $cols->setQuery('SHOW COLUMNS FROM ' . rex::getTablePrefix() . 'article_slice');
165 
166         $maxPriority = rex_sql::factory()->getArray(
167             'SELECT `ctype_id`, MAX(`priority`) as max FROM ' . rex::getTable('article_slice') . ' WHERE `article_id` = :to_id AND `clang_id` = :to_clang AND `revision` = :revision GROUP BY `ctype_id`',
168             ['to_id' => $to_id, 'to_clang' => $to_clang, 'revision' => $revision]
169         );
170         $maxPriority = array_column($maxPriority, 'max', 'ctype_id');
171 
172         $user = self::getUser();
173 
174         foreach ($gc as $slice) {
175             foreach ($cols as $col) {
176                 $colname = $col->getValue('Field');
177                 if ($colname == 'clang_id') {
178                     $value = $to_clang;
179                 } elseif ($colname == 'article_id') {
180                     $value = $to_id;
181                 } elseif ($colname == 'priority') {
182                     $ctypeId = $slice->getValue('ctype_id');
183                     $value = $slice->getValue($colname) + (isset($maxPriority[$ctypeId]) ? $maxPriority[$ctypeId] : 0);
184                 } else {
185                     $value = $slice->getValue($colname);
186                 }
187 
188                 // collect all affected ctypes
189                 if ($colname == 'ctype_id') {
190                     $ctypes[$value] = $value;
191                 }
192 
193                 if ($colname != 'id') {
194                     $ins->setValue($colname, $value);
195                 }
196             }
197 
198             $ins->addGlobalUpdateFields($user);
199             $ins->addGlobalCreateFields($user);
200             $ins->setTable(rex::getTablePrefix() . 'article_slice');
201             $ins->insert();
202         }
203 
204         foreach ($ctypes as $ctype) {
205             // reorg slices
206             rex_sql_util::organizePriorities(
207                 rex::getTable('article_slice'),
208                 'priority',
209                 'article_id=' . (int) $to_id . ' AND clang_id=' . (int) $to_clang . ' AND ctype_id=' . (int) $ctype . ' AND revision=' . (int) $revision,
210                 'priority, updatedate'
211             );
212         }
213 
214         rex_article_cache::deleteContent($to_id, $to_clang);
215 
216         return true;
217     }
218 
219     /**
220      * Generiert den Artikel-Cache des Artikelinhalts.
221      *
222      * @param int $article_id Id des zu generierenden Artikels
223      * @param int $clang      ClangId des Artikels
224      *
225      * @return bool TRUE bei Erfolg, FALSE wenn eine ungütlige article_id übergeben wird, sonst eine Fehlermeldung
226      */
227     public static function generateArticleContent($article_id, $clang = null)
228     {
229         foreach (rex_clang::getAllIds() as $_clang) {
230             if ($clang !== null && $clang != $_clang) {
231                 continue;
232             }
233 
234             $CONT = new rex_article_content_base();
235             $CONT->setCLang($_clang);
236             $CONT->setEval(false); // Content nicht ausführen, damit in Cachedatei gespeichert werden kann
237             if (!$CONT->setArticleId($article_id)) {
238                 return false;
239             }
240 
241             // --------------------------------------------------- Artikelcontent speichern
242             $article_content_file = rex_path::addonCache('structure', "$article_id.$_clang.content");
243             $article_content = $CONT->getArticle();
244 
245             // ----- EXTENSION POINT
246             $article_content = rex_extension::registerPoint(new rex_extension_point('GENERATE_FILTER', $article_content, [
247                 'id' => $article_id,
248                 'clang' => $_clang,
249                 'article' => $CONT,
250             ]));
251 
252             if (rex_file::put($article_content_file, $article_content) === false) {
253                 return rex_i18n::msg('article_could_not_be_generated') . ' ' . rex_i18n::msg('check_rights_in_directory') . rex_path::addonCache('structure');
254             }
255         }
256 
257         return true;
258     }
259 
260     private static function getUser()
261     {
262         if (rex::getUser()) {
263             return rex::getUser()->getLogin();
264         }
265 
266         if (method_exists(rex::class, 'getEnvironment')) {
267             return rex::getEnvironment();
268         }
269 
270         return 'frontend';
271     }
272 }
273