Passed
Push — CHECK_API ( 78ffdd...fa4f39 )
by Rafael
41:29
created

WebsitePage   F

Complexity

Total Complexity 101

Size/Duplication

Total Lines 860
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 458
dl 0
loc 860
rs 2
c 0
b 0
f 0
wmc 101

13 Methods

Rating   Name   Duplication   Size   Complexity  
A create() 0 16 2
A __construct() 0 3 1
C getNomUrl() 0 45 13
A LibStatut() 0 20 4
C countAll() 0 58 15
C fetch() 0 109 12
B delete() 0 51 10
C createFromClone() 0 74 11
A getLibStatut() 0 3 1
F fetchAll() 0 135 25
A update() 0 29 5
A initAsSpecimen() 0 27 1
A setCategories() 0 3 1

How to fix   Complexity   

Complex Class

Complex classes like WebsitePage often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

While breaking up the class, it is a good idea to analyze how other classes use WebsitePage, and based on these observations, apply Extract Interface, too.

1
<?php
2
3
/* Copyright (C) 2007-2018  Laurent Destailleur         <[email protected]>
4
 * Copyright (C) 2014       Juanjo Menent               <[email protected]>
5
 * Copyright (C) 2015       Florian Henry               <[email protected]>
6
 * Copyright (C) 2015       Raphaël Doursenaud          <[email protected]>
7
 * Copyright (C) 2020 	    Nicolas ZABOURI		        <[email protected]>
8
 * Copyright (C) 2024       Frédéric France             <[email protected]>
9
 * Copyright (C) 2024		MDW							<[email protected]>
10
 * Copyright (C) 2024       Rafael San José             <[email protected]>
11
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 3 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program. If not, see <https://www.gnu.org/licenses/>.
24
 */
25
26
namespace Dolibarr\Code\Website\Classes;
27
28
use Dolibarr\Code\Categories\Classes\Categorie;
29
use Dolibarr\Core\Base\CommonObject;
30
31
/**
32
 * \file    htdocs/website/class/websitepage.class.php
33
 * \ingroup website
34
 * \brief   File for the CRUD class of websitepage (Create/Read/Update/Delete)
35
 */
36
37
// Put here all includes required by your class file
38
39
//use Dolibarr\Code\Societe\Classes\Societe;
40
//
41
/**
42
 * Class Websitepage
43
 */
44
class WebsitePage extends CommonObject
45
{
46
const STATUS_DRAFT = 0;
47
const STATUS_VALIDATED = 1;
48
    /**
49
     * @var string Id to identify managed objects
50
     */
51
    public $element = 'websitepage';
52
    /**
53
     * @var string Name of table without prefix where object is stored
54
     */
55
    public $table_element = 'website_page';
56
    /**
57
     * @var string String with name of icon for websitepage. Must be the part after the 'object_' into object_myobject.png
58
     */
59
    public $picto = 'file-code';
60
    /**
61
     * @var string  Field with ID of parent key if this field has a parent or for child tables
62
     */
63
    public $fk_element = 'fk_website_page';
64
    /**
65
     * @var int ID
66
     */
67
    public $fk_website;        // If translation of another page
68
public $fk_page;
69
    public $pageurl;
70
    public $aliasalt;
71
    public $type_container;
72
    /**
73
     * @var string title
74
     */
75
    public $title;
76
    /**
77
     * @var string description
78
     */
79
    public $description;
80
    /**
81
     * @var string image
82
     */
83
    public $image;
84
    /**
85
     * @var string keywords
86
     */
87
    public $keywords;
88
    /**
89
     * @var string language code ('en', 'fr', 'en-gb', ..)
90
     */
91
    public $lang;
92
    public $allowed_in_frames;
93
    public $htmlheader;
94
    public $content;
95
    public $grabbed_from;
96
    /**
97
     * @var int Status
98
     */
99
    public $status;
100
    /**
101
     * @var integer|string date_creation
102
     */
103
    public $date_creation;
104
    /**
105
     * @var integer|string date_modification
106
     */
107
    public $date_modification;
108
    public $fk_user_creat;
109
    public $fk_user_modif;
110
    /**
111
     * @var string author_alias
112
     */
113
    public $author_alias;
114
    /**
115
     * @var string path of external object
116
     */
117
    public $object_type;
118
    /**
119
     * @var string id of external object
120
     */
121
    public $fk_object;
122
    /**
123
     * @var int         Another ID that is the $id but with an offset so that ID of pages of the website start at 1
124
     */
125
    public $newid;         // offline
126
        /**
127
     * @var array<string,array{type:string,label:string,enabled:int<0,2>|string,position:int,notnull?:int,visible:int,noteditable?:int,default?:string,index?:int,foreignkey?:string,searchall?:int,isameasure?:int,css?:string,csslist?:string,help?:string,showoncombobox?:int,disabled?:int,arrayofkeyval?:array<int,string>,comment?:string}>  Array with all fields and their property. Do not use it as a static var. It may be modified by constructor.
0 ignored issues
show
Documentation Bug introduced by
The doc comment array<string,array{type:...ring>,comment?:string}> at position 16 could not be parsed: Expected '}' at position 16, but found 'int'.
Loading history...
128
     */
129
    public $fields = array(
130
        'rowid' => array('type' => 'integer', 'label' => 'TechnicalID', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'index' => 1, 'position' => 1, 'comment' => 'Id'),
131
        'pageurl' => array('type' => 'varchar(16)', 'label' => 'WEBSITE_PAGENAME', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'index' => 1, 'position' => 10, 'searchall' => 1, 'comment' => 'Ref/alias of page'),
132
        'aliasalt' => array('type' => 'varchar(255)', 'label' => 'AliasAlt', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'index' => 0, 'position' => 11, 'searchall' => 0, 'comment' => 'Alias alternative of page'),
133
        'type_container' => array('type' => 'varchar(16)', 'label' => 'Type', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'index' => 0, 'position' => 12, 'comment' => 'Type of container'),
134
        'title' => array('type' => 'varchar(255)', 'label' => 'Label', 'enabled' => 1, 'visible' => 1, 'position' => 30, 'searchall' => 1, 'help' => 'UseTextBetween5And70Chars'),
135
        'description' => array('type' => 'varchar(255)', 'label' => 'Description', 'enabled' => 1, 'visible' => 1, 'position' => 30, 'searchall' => 1),
136
        'image' => array('type' => 'varchar(255)', 'label' => 'Image', 'enabled' => 1, 'visible' => 1, 'position' => 32, 'searchall' => 0, 'help' => 'Relative path of media. Used if Type is "blogpost"'),
137
        'keywords' => array('type' => 'varchar(255)', 'label' => 'Keywords', 'enabled' => 1, 'visible' => 1, 'position' => 45, 'searchall' => 0),
138
        'lang' => array('type' => 'varchar(6)', 'label' => 'Lang', 'enabled' => 1, 'notnull' => -1, 'visible' => 1, 'position' => 45, 'searchall' => 0),
139
        //'status'        =>array('type'=>'integer',      'label'=>'Status',           'enabled'=>1, 'visible'=>1,  'index'=>true,   'position'=>1000),
140
        'fk_website' => array('type' => 'integer', 'label' => 'WebsiteId', 'enabled' => 1, 'visible' => 1, 'notnull' => 1, 'position' => 40, 'searchall' => 0, 'foreignkey' => 'websitepage.rowid'),
141
        'fk_page' => array('type' => 'integer', 'label' => 'ParentPageId', 'enabled' => 1, 'visible' => 1, 'notnull' => -1, 'position' => 45, 'searchall' => 0, 'foreignkey' => 'website.rowid'),
142
        'allowed_in_frames' => array('type' => 'integer', 'label' => 'AllowedInFrames', 'enabled' => 1, 'visible' => -1, 'position' => 48, 'searchall' => 0, 'default' => '0'),
143
        'htmlheader' => array('type' => 'html', 'label' => 'HtmlHeader', 'enabled' => 1, 'visible' => 0, 'position' => 50, 'searchall' => 0),
144
        'content' => array('type' => 'mediumtext', 'label' => 'Content', 'enabled' => 1, 'visible' => 0, 'position' => 51, 'searchall' => 0),
145
        'grabbed_from' => array('type' => 'varchar(255)', 'label' => 'GrabbedFrom', 'enabled' => 1, 'visible' => 1, 'index' => 1, 'position' => 400, 'comment' => 'URL page content was grabbed from'),
146
        'date_creation' => array('type' => 'datetime', 'label' => 'DateCreation', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 500),
147
        'tms' => array('type' => 'timestamp', 'label' => 'DateModification', 'enabled' => 1, 'visible' => -1, 'notnull' => 1, 'position' => 501),
148
        //'date_valid'    =>array('type'=>'datetime',     'label'=>'DateValidation',     'enabled'=>1, 'visible'=>-1, 'position'=>502),
149
        'fk_user_creat' => array('type' => 'integer', 'label' => 'UserAuthor', 'enabled' => 1, 'visible' => -1, 'notnull' => true, 'position' => 510),
150
        'author_alias' => array('type' => 'varchar(64)', 'label' => 'AuthorAlias', 'enabled' => 1, 'visible' => -1, 'index' => 0, 'position' => 511, 'comment' => 'Author alias'),
151
        'fk_user_modif' => array('type' => 'integer', 'label' => 'UserModif', 'enabled' => 1, 'visible' => -1, 'position' => 512),
152
        //'fk_user_valid' =>array('type'=>'integer',      'label'=>'UserValidation',        'enabled'=>1, 'visible'=>-1, 'position'=>512),
153
        'import_key' => array('type' => 'varchar(14)', 'label' => 'ImportId', 'enabled' => 1, 'visible' => -1, 'index' => 1, 'position' => 1000, 'notnull' => -1),
154
        'object_type' => array('type' => 'varchar(255)', 'label' => 'ObjectType', 'enabled' => 1, 'visible' => 0, 'position' => 46, 'searchall' => 0, 'help' => ''),
155
        'fk_object' => array('type' => 'varchar(255)', 'label' => 'ObjectId', 'enabled' => 1, 'visible' => 0, 'position' => 47, 'searchall' => 0, 'help' => '')
156
    );     // online
157
158
159
    /**
160
     *  'type' if the field format ('integer', 'integer:ObjectClass:PathToClass[:AddCreateButtonOrNot[:Filter]]', 'varchar(x)', 'double(24,8)', 'real', 'price', 'text', 'html', 'date', 'datetime', 'timestamp', 'duration', 'mail', 'phone', 'url', 'password')
161
     *         Note: Filter can be a string like "(t.ref:like:'SO-%') or (t.date_creation:<:'20160101') or (t.nature:is:NULL)"
162
     *  'label' the translation key.
163
     *  'enabled' is a condition when the field must be managed (Example: 1 or 'getDolGlobalString("MY_SETUP_PARAM")'
164
     *  'position' is the sort order of field.
165
     *  'notnull' is set to 1 if not null in database. Set to -1 if we must set data to null if empty ('' or 0).
166
     *  'visible' says if field is visible in list (Examples: 0=Not visible, 1=Visible on list and create/update/view forms, 2=Visible on list only, 3=Visible on create/update/view form only (not list), 4=Visible on list and update/view form only (not create). 5=Visible on list and view only (not create/not update). Using a negative value means field is not shown by default on list but can be selected for viewing)
167
     *  'noteditable' says if field is not editable (1 or 0)
168
     *  'default' is a default value for creation (can still be overwrote by the Setup of Default Values if field is editable in creation form). Note: If default is set to '(PROV)' and field is 'ref', the default value will be set to '(PROVid)' where id is rowid when a new record is created.
169
     *  'index' if we want an index in database.
170
     *  'foreignkey'=>'tablename.field' if the field is a foreign key (it is recommended to name the field fk_...).
171
     *  'searchall' is 1 if we want to search in this field when making a search from the quick search button.
172
     *  'isameasure' must be set to 1 if you want to have a total on list for this field. Field type must be summable like integer or double(24,8).
173
     *  'css' is the CSS style to use on field. For example: 'maxwidth200'
174
     *  'help' is a string visible as a tooltip on field
175
     *  'showoncombobox' if value of the field must be visible into the label of the combobox that list record
176
     *  'disabled' is 1 if we want to have the field locked by a 'disabled' attribute. In most cases, this is never set into the definition of $fields into class, but is set dynamically by some part of code.
177
     *  'arrayofkeyval' to set list of value if type is a list of predefined values. For example: array("0"=>"Draft","1"=>"Active","-1"=>"Cancel")
178
     *  'comment' is not used. You can store here any text of your choice. It is not used by application.
179
     *
180
     *  Note: To have value dynamic, you can set value to 0 in definition and edit the value on the fly into the constructor.
181
     */
182
183
    // BEGIN MODULEBUILDER PROPERTIES
184
    /**
185
     * @var string[]    List of child tables. To know object to delete on cascade.
186
     */
187
    protected $childtablesoncascade = array('categorie_website_page');
188
    // END MODULEBUILDER PROPERTIES
189
190
    /**
191
     * Constructor
192
     *
193
     * @param DoliDB $db Database handler
194
     */
195
    public function __construct(DoliDB $db)
0 ignored issues
show
Bug introduced by
The type Dolibarr\Code\Website\Classes\DoliDB was not found. Did you mean DoliDB? If so, make sure to prefix the type with \.
Loading history...
196
    {
197
        $this->db = $db;
198
    }
199
200
    /**
201
     * Return array of all web site pages.
202
     *
203
     * @param string $websiteid Web site
204
     * @param string $sortorder Sort Order
205
     * @param string $sortfield Sort field
206
     * @param int $limit limit
207
     * @param int $offset Offset
208
     * @param string|array $filter Filter as an Universal Search string.
209
     *                                      Example: '((client:=:1) OR ((client:>=:2) AND (client:<=:3))) AND (client:!=:8) AND (nom:like:'a%')'
210
     * @param string $filtermode No more used
211
     * @return WebSitePage[]|int<-1,-1>     int <0 if KO, array of pages if OK
212
     */
213
    public function fetchAll($websiteid = '', $sortorder = '', $sortfield = '', $limit = 0, $offset = 0, $filter = '', $filtermode = 'AND')
214
    {
215
        dol_syslog(__METHOD__, LOG_DEBUG);
216
217
        $records = array();
218
219
        $sql = 'SELECT';
220
        $sql .= ' t.rowid,';
221
        $sql .= " t.fk_website,";
222
        $sql .= " t.type_container,";
223
        $sql .= " t.pageurl,";
224
        $sql .= " t.aliasalt,";
225
        $sql .= " t.title,";
226
        $sql .= " t.description,";
227
        $sql .= " t.image,";
228
        $sql .= " t.keywords,";
229
        $sql .= " t.htmlheader,";
230
        $sql .= " t.content,";
231
        $sql .= " t.lang,";
232
        $sql .= " t.fk_page,";
233
        $sql .= " t.allowed_in_frames,";
234
        $sql .= " t.status,";
235
        $sql .= " t.grabbed_from,";
236
        $sql .= " t.date_creation,";
237
        $sql .= " t.tms as date_modification,";
238
        $sql .= " t.fk_user_creat,";
239
        $sql .= " t.author_alias,";
240
        $sql .= " t.fk_user_modif,";
241
        $sql .= " t.import_key,";
242
        $sql .= " t.object_type,";
243
        $sql .= " t.fk_object";
244
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
245
        if (!empty($websiteid)) {
246
            $sql .= ' WHERE t.fk_website = ' . ((int)$websiteid);
247
        }
248
249
        // Deprecated. If we receive an array, we use it. Prefer using the USF syntax.
250
        if (is_array($filter)) {
251
            $sqlwhere = array();
252
253
            if (count($filter) > 0) {
254
                foreach ($filter as $key => $value) {
255
                    if ($key == 't.rowid' || $key == 'rowid' || $key == 't.fk_website' || $key == 'fk_website' || $key == 'status' || $key == 't.status') {
256
                        $sqlwhere[] = $key . " = " . ((int)$value);
257
                    } elseif ($key == 'type_container' || $key == 't.type_container') {
258
                        $sqlwhere[] = $key . " = '" . $this->db->escape($value) . "'";
259
                    } elseif ($key == 'lang' || $key == 't.lang') {
260
                        $listoflang = array();
261
                        $foundnull = 0;
262
                        foreach (explode(',', $value) as $tmpvalue) {
263
                            if ($tmpvalue == 'null') {
264
                                $foundnull++;
265
                                continue;
266
                            }
267
                            $listoflang[] = "'" . $this->db->escape(substr(str_replace("'", '', $tmpvalue), 0, 2)) . "'";
268
                        }
269
                        $stringtouse = $this->db->sanitize($key) . " IN (" . $this->db->sanitize(implode(',', $listoflang), 1) . ")";
270
                        if ($foundnull) {
271
                            $stringtouse = "(" . $stringtouse . " OR " . $this->db->sanitize($key) . " IS NULL)";
272
                        }
273
                        $sqlwhere[] = $stringtouse;
274
                    } else {
275
                        $sqlwhere[] = $this->db->sanitize($key) . " LIKE '%" . $this->db->escape($value) . "%'";
276
                    }
277
                }
278
            }
279
            if (count($sqlwhere) > 0) {
280
                if (!empty($websiteid)) {
281
                    $sql .= " AND (" . implode(' ' . $this->db->escape($filtermode) . ' ', $sqlwhere) . ')';
282
                } else {
283
                    $sql .= " WHERE " . implode(' ' . $this->db->escape($filtermode) . ' ', $sqlwhere);
284
                }
285
            }
286
287
            $filter = '';
288
        }
289
290
        $errormessage = '';
291
        $sql .= forgeSQLFromUniversalSearchCriteria($filter, $errormessage);
292
        if ($errormessage) {
293
            $this->errors[] = $errormessage;
294
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
295
            return -1;
296
        }
297
298
        if (!empty($sortfield)) {
299
            $sql .= $this->db->order($sortfield, $sortorder);
300
        }
301
        if (!empty($limit)) {
302
            $sql .= $this->db->plimit($limit, $offset);
303
        }
304
305
        $resql = $this->db->query($sql);
306
        if ($resql) {
307
            $num = $this->db->num_rows($resql);
308
309
            while ($obj = $this->db->fetch_object($resql)) {
310
                $record = new self($this->db);
311
312
                $record->id = $obj->rowid;
313
                $record->fk_website = $obj->fk_website;
314
                $record->type_container = $obj->type_container;
315
                $record->pageurl = $obj->pageurl;
316
                $record->aliasalt = preg_replace('/,+$/', '', preg_replace('/^,+/', '', $obj->aliasalt));
317
                $record->title = $obj->title;
318
                $record->description = $obj->description;
319
                $record->image = $obj->image;
320
                $record->keywords = $obj->keywords;
321
                $record->htmlheader = $obj->htmlheader;
322
                $record->content = $obj->content;
323
                $record->lang = $obj->lang;
324
                $record->fk_page = $obj->fk_page;
325
                $record->allowed_in_frames = $obj->allowed_in_frames;
326
                $record->status = $obj->status;
327
                $record->grabbed_from = $obj->grabbed_from;
328
                $record->date_creation = $this->db->jdate($obj->date_creation);
329
                $record->date_modification = $this->db->jdate($obj->date_modification);
330
                $record->fk_user_creat = $obj->fk_user_creat;
331
                $record->author_alias = $obj->author_alias;
332
                $record->fk_user_modif = $obj->fk_user_modif;
333
                $record->import_key = $obj->import_key;
334
                $record->object_type = $obj->object_type;
335
                $record->fk_object = $obj->fk_object;
336
                //var_dump($record->id);
337
                $records[$record->id] = $record;
338
            }
339
            $this->db->free($resql);
340
341
            return $records;
342
        } else {
343
            $this->error = 'Error ' . $this->db->lasterror();
344
            $this->errors[] = $this->error;
345
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
346
347
            return -1;
348
        }
349
    }
350
351
    /**
352
     * Count objects in the database.
353
     *
354
     * @param string $websiteid Web site
355
     * @param array $filter Filter array
356
     * @param string $filtermode Filter mode (AND or OR)
357
     * @return int                       int <0 if KO, array of pages if OK
358
     */
359
    public function countAll($websiteid, array $filter = array(), $filtermode = 'AND')
360
    {
361
        dol_syslog(__METHOD__, LOG_DEBUG);
362
363
        $result = 0;
364
365
        $sql = 'SELECT COUNT(t.rowid) as nb';
366
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
367
        $sql .= ' WHERE t.fk_website = ' . ((int)$websiteid);
368
369
        // Manage filter (same than into fetchAll)
370
        $sqlwhere = array();
371
        if (count($filter) > 0) {
372
            foreach ($filter as $key => $value) {
373
                if ($key == 't.rowid' || $key == 't.fk_website' || $key == 'status') {
374
                    $sqlwhere[] = $key . " = " . ((int)$value);
375
                } elseif ($key == 'type_container') {
376
                    $sqlwhere[] = $key . " = '" . $this->db->escape($value) . "'";
377
                } elseif ($key == 'lang' || $key == 't.lang') {
378
                    $listoflang = array();
379
                    $foundnull = 0;
380
                    foreach (explode(',', $value) as $tmpvalue) {
381
                        if ($tmpvalue == 'null') {
382
                            $foundnull++;
383
                            continue;
384
                        }
385
                        $listoflang[] = "'" . $this->db->escape(substr(str_replace("'", '', $tmpvalue), 0, 2)) . "'";
386
                    }
387
                    $stringtouse = $key . " IN (" . $this->db->sanitize(implode(',', $listoflang), 1) . ")";
388
                    if ($foundnull) {
389
                        $stringtouse = "(" . $stringtouse . " OR " . $key . " IS NULL)";
390
                    }
391
                    $sqlwhere[] = $stringtouse;
392
                } else {
393
                    $sqlwhere[] = $key . " LIKE '%" . $this->db->escape($value) . "%'";
394
                }
395
            }
396
        }
397
        if (count($sqlwhere) > 0) {
398
            $sql .= ' AND (' . implode(' ' . $this->db->escape($filtermode) . ' ', $sqlwhere) . ')';
399
        }
400
401
        $resql = $this->db->query($sql);
402
        if ($resql) {
403
            $obj = $this->db->fetch_object($resql);
404
            if ($obj) {
405
                $result = $obj->nb;
406
            }
407
408
            $this->db->free($resql);
409
410
            return $result;
411
        } else {
412
            $this->error = 'Error ' . $this->db->lasterror();
413
            $this->errors[] = $this->error;
414
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
415
416
            return -1;
417
        }
418
    }
419
420
    /**
421
     * Update object into database
422
     *
423
     * @param User $user User that modifies
424
     * @param int $notrigger 0=launch triggers after, 1=disable triggers
425
     * @return int             Return integer <0 if KO, >0 if OK
426
     */
427
    public function update(User $user, $notrigger = 0)
428
    {
429
        $this->description = dol_trunc($this->description, 255, 'right', 'utf-8', 1);
430
        $this->keywords = dol_trunc($this->keywords, 255, 'right', 'utf-8', 1);
431
        if ($this->aliasalt) {
432
            $this->aliasalt = ',' . preg_replace('/,+$/', '', preg_replace('/^,+/', '', $this->aliasalt)) . ','; // content in database must be ',xxx,...,yyy,'
433
        }
434
435
        $this->pageurl = preg_replace('/[^a-z0-9\-\_]/i', '', $this->pageurl);
436
        $this->pageurl = preg_replace('/\-\-+/', '-', $this->pageurl);
437
        $this->pageurl = preg_replace('/^\-/', '', $this->pageurl);
438
439
        // Remove spaces and be sure we have main language only
440
        $this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en
441
442
        if ($this->fk_page > 0) {
443
            if (empty($this->lang)) {
444
                $this->error = "ErrorLanguageMandatoryIfPageSetAsTranslationOfAnother";
445
                return -1;
446
            }
447
            $tmppage = new WebsitePage($this->db);
448
            $tmppage->fetch($this->fk_page);
449
            if ($tmppage->lang == $this->lang) {
450
                $this->error = "ErrorLanguageOfTranslatedPageIsSameThanThisPage";
451
                return -1;
452
            }
453
        }
454
455
        return $this->updateCommon($user, $notrigger);
456
    }
457
458
    /**
459
     * Load object in memory from the database
460
     *
461
     * @param int $id Id object.
462
     *                                  - If this is 0, the value into $page will be used. If not found or $page not defined, the default page of website_id will be used or the first page found if not set.
463
     *                                  - If value is < 0, we must exclude this ID.
464
     * @param string $website_id Web site id (page name must also be filled if this parameter is used)
465
     * @param string $page Page name (website id must also be filled if this parameter is used). Example 'myaliaspage' or 'fr/myaliaspage'
466
     * @param string $aliasalt Alternative alias to search page (slow)
467
     * @return int<-1,1>                Return integer <0 if KO, 0 if not found, >0 if OK
468
     */
469
    public function fetch($id, $website_id = null, $page = null, $aliasalt = null)
470
    {
471
        dol_syslog(__METHOD__, LOG_DEBUG);
472
473
        $sql = 'SELECT';
474
        $sql .= ' t.rowid,';
475
        $sql .= " t.fk_website,";
476
        $sql .= ' t.type_container,';
477
        $sql .= " t.pageurl,";
478
        $sql .= " t.aliasalt,";
479
        $sql .= " t.title,";
480
        $sql .= " t.description,";
481
        $sql .= " t.image,";
482
        $sql .= " t.keywords,";
483
        $sql .= " t.htmlheader,";
484
        $sql .= " t.content,";
485
        $sql .= " t.lang,";
486
        $sql .= " t.fk_page,";
487
        $sql .= " t.allowed_in_frames,";
488
        $sql .= " t.status,";
489
        $sql .= " t.grabbed_from,";
490
        $sql .= " t.date_creation,";
491
        $sql .= " t.tms as date_modification,";
492
        $sql .= " t.fk_user_creat,";
493
        $sql .= " t.author_alias,";
494
        $sql .= " t.fk_user_modif,";
495
        $sql .= " t.import_key,";
496
        $sql .= " t.object_type,";
497
        $sql .= " t.fk_object";
498
        $sql .= ' FROM ' . MAIN_DB_PREFIX . $this->table_element . ' as t';
499
        //$sql .= ' WHERE entity IN ('.getEntity('website').')';       // entity is on website level
500
        $sql .= ' WHERE 1 = 1';
501
        if ($id > 0) {
502
            $sql .= ' AND t.rowid = ' . ((int)$id);
503
        } else {
504
            if ($id < 0) {
505
                $sql .= ' AND t.rowid <> ' . abs($id);
506
            }
507
            if (null !== $website_id) {
508
                $sql .= " AND t.fk_website = '" . $this->db->escape($website_id) . "'";
509
                if ($page) {
510
                    $pagetouse = $page;
511
                    $langtouse = '';
512
                    $tmppage = explode('/', $page);
513
                    if (!empty($tmppage[1])) {
514
                        $pagetouse = $tmppage[1];
515
                        if (strlen($tmppage[0])) {
516
                            $langtouse = $tmppage[0];
517
                        }
518
                    }
519
                    $sql .= " AND t.pageurl = '" . $this->db->escape($pagetouse) . "'";
520
                    if ($langtouse) {
521
                        $sql .= " AND t.lang = '" . $this->db->escape($langtouse) . "'";
522
                    }
523
                }
524
                if ($aliasalt) {
525
                    $sql .= " AND (t.aliasalt LIKE '%," . $this->db->escape($aliasalt) . ",%' OR t.aliasalt LIKE '%, " . $this->db->escape($aliasalt) . ",%')";
526
                }
527
            }
528
        }
529
        $sql .= $this->db->plimit(1);
530
531
        $resql = $this->db->query($sql);
532
        if ($resql) {
533
            $numrows = $this->db->num_rows($resql);
534
            if ($numrows) {
535
                $obj = $this->db->fetch_object($resql);
536
537
                $this->id = $obj->rowid;
538
539
                $this->fk_website = $obj->fk_website;
540
                $this->type_container = $obj->type_container;
541
542
                $this->pageurl = $obj->pageurl;
543
                $this->ref = $obj->pageurl;
544
                $this->aliasalt = preg_replace('/,+$/', '', preg_replace('/^,+/', '', $obj->aliasalt));
545
546
                $this->title = $obj->title;
547
                $this->description = $obj->description;
548
                $this->image = $obj->image;
549
                $this->keywords = $obj->keywords;
550
                $this->htmlheader = $obj->htmlheader;
551
                $this->content = $obj->content;
552
                $this->lang = $obj->lang;
553
                $this->fk_page = $obj->fk_page;
554
                $this->allowed_in_frames = $obj->allowed_in_frames;
555
                $this->status = $obj->status;
556
                $this->grabbed_from = $obj->grabbed_from;
557
                $this->date_creation = $this->db->jdate($obj->date_creation);
558
                $this->date_modification = $this->db->jdate($obj->date_modification);
559
                $this->fk_user_creat = $obj->fk_user_creat;
560
                $this->author_alias = $obj->author_alias;
561
                $this->fk_user_modif = $obj->fk_user_modif;
562
                $this->import_key = $obj->import_key;
563
                $this->object_type = $obj->object_type;
564
                $this->fk_object = $obj->fk_object;
565
            }
566
            $this->db->free($resql);
567
568
            if ($numrows) {
569
                return 1;
570
            } else {
571
                return 0;
572
            }
573
        } else {
574
            $this->errors[] = 'Error ' . $this->db->lasterror();
575
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
576
577
            return -1;
578
        }
579
    }
580
581
    /**
582
     * Delete object in database
583
     *
584
     * @param User $user User that deletes
585
     * @param int $notrigger 0=launch triggers after, 1=disable triggers
586
     * @return int              Return integer <0 if KO, >0 if OK
587
     */
588
    public function delete(User $user, $notrigger = 0)
589
    {
590
        global $conf;
591
592
        $error = 0;
593
594
        // Delete all child tables
595
        if (!$error) {
596
            foreach ($this->childtablesoncascade as $table) {
597
                $sql = "DELETE FROM " . MAIN_DB_PREFIX . $table;
598
                $sql .= " WHERE fk_website_page = " . (int)$this->id;
599
600
                $result = $this->db->query($sql);
601
                if (!$result) {
602
                    $error++;
603
                    $this->errors[] = $this->db->lasterror();
604
                    break;
605
                }
606
            }
607
        }
608
609
        if (!$error) {
610
            $result = $this->deleteCommon($user, $notrigger);
611
            if ($result <= 0) {
612
                $error++;
613
            }
614
        }
615
616
        if (!$error) {
617
            $websiteobj = new Website($this->db);
618
            $result = $websiteobj->fetch($this->fk_website);
619
620
            if ($result > 0) {
621
                global $dolibarr_main_data_root;
622
                $pathofwebsite = $dolibarr_main_data_root . ($conf->entity > 1 ? '/' . $conf->entity : '') . '/website/' . $websiteobj->ref;
623
624
                $filealias = $pathofwebsite . '/' . $this->pageurl . '.php';
625
                $filetpl = $pathofwebsite . '/page' . $this->id . '.tpl.php';
626
627
                dol_delete_file($filealias);
628
                dol_delete_file($filetpl);
629
            } else {
630
                $this->error = $websiteobj->error;
631
                $this->errors = $websiteobj->errors;
632
            }
633
        }
634
635
        if (!$error) {
636
            return 1;
637
        } else {
638
            return -1;
639
        }
640
    }
641
642
    /**
643
     * Load an object from its id and create a new one in database
644
     *
645
     * @param User $user User making the clone
646
     * @param int $fromid Id of object to clone
647
     * @param string $newref New ref/alias of page
648
     * @param string $newlang New language
649
     * @param int $istranslation 1=New page is a translation of the cloned page.
650
     * @param int $newwebsite 0=Same web site, >0=Id of new website
651
     * @param string $newtitle New title
652
     * @return  mixed                       New object created, <0 if KO
653
     */
654
    public function createFromClone(User $user, $fromid, $newref, $newlang = '', $istranslation = 0, $newwebsite = 0, $newtitle = '')
655
    {
656
        global $hookmanager, $langs;
657
658
        $now = dol_now();
659
        $error = 0;
660
661
        dol_syslog(__METHOD__, LOG_DEBUG);
662
663
        $object = new self($this->db);
664
665
        // Clean parameters
666
        if (empty($newref) && !empty($newtitle)) {
667
            $newref = strtolower(dol_sanitizeFileName(preg_replace('/\s+/', '-', $newtitle), '-', 1));
668
        }
669
670
        // Check parameters
671
        if (empty($newref)) {
672
            $langs->load("errors");
673
            $this->error = $langs->trans("ErrorFieldRequired", $langs->transnoentitiesnoconv("WEBSITE_TITLE"));
674
            return -1;
675
        }
676
677
        $this->db->begin();
678
679
        // Load source object
680
        $object->fetch($fromid);
681
        // Reset object
682
        $object->id = 0;
683
684
        // Clear fields
685
        $object->ref = $newref;
686
        $object->pageurl = $newref;
687
        $object->aliasalt = '';
688
        $object->fk_user_creat = $user->id;
689
        $object->author_alias = '';
690
        $object->date_creation = $now;
691
        $object->title = ($newtitle == '1' ? $object->title : ($newtitle ? $newtitle : $object->title));
692
        $object->description = $object->title;
693
        if (!empty($newlang)) {
694
            $object->lang = $newlang;
695
        }
696
        if ($istranslation) {
697
            $object->fk_page = $fromid;
698
        } else {
699
            $object->fk_page = 0;
700
        }
701
        if (!empty($newwebsite)) {
702
            $object->fk_website = $newwebsite;
703
        }
704
        $object->import_key = '';
705
        $object->status = self::STATUS_DRAFT;
706
707
        // Create clone
708
        $object->context['createfromclone'] = 'createfromclone';
709
        $result = $object->create($user);
710
        if ($result < 0) {
711
            $error++;
712
            $this->error = $object->error;
713
            $this->errors = $object->errors;
714
            dol_syslog(__METHOD__ . ' ' . implode(',', $this->errors), LOG_ERR);
715
        }
716
717
        unset($object->context['createfromclone']);
718
719
        // End
720
        if (!$error) {
721
            $this->db->commit();
722
723
            return $object;
724
        } else {
725
            $this->db->rollback();
726
727
            return -1;
728
        }
729
    }
730
731
    /**
732
     * Create object into database
733
     *
734
     * @param User $user User that creates
735
     * @param int $notrigger 0=launch triggers after, 1=disable triggers
736
     * @return int             Return integer <0 if KO, Id of created object if OK
737
     */
738
    public function create(User $user, $notrigger = 0)
739
    {
740
        $this->description = dol_trunc($this->description, 255, 'right', 'utf-8', 1);
741
        $this->keywords = dol_trunc($this->keywords, 255, 'right', 'utf-8', 1);
742
        if ($this->aliasalt) {
743
            $this->aliasalt = ',' . preg_replace('/,+$/', '', preg_replace('/^,+/', '', $this->aliasalt)) . ','; // content in database must be ',xxx,...,yyy,'
744
        }
745
746
        $this->pageurl = preg_replace('/[^a-z0-9\-\_]/i', '', $this->pageurl);
747
        $this->pageurl = preg_replace('/\-\-+/', '-', $this->pageurl);
748
        $this->pageurl = preg_replace('/^\-/', '', $this->pageurl);
749
750
        // Remove spaces and be sure we have main language only
751
        $this->lang = preg_replace('/[_-].*$/', '', trim($this->lang)); // en_US or en-US -> en
752
753
        return $this->createCommon($user, $notrigger);
754
    }
755
756
    /**
757
     *  Return a link to the user card (with optionally the picto)
758
     *  Use this->id,this->lastname, this->firstname
759
     *
760
     * @param int $withpicto Include picto in link (0=No picto, 1=Include picto into link, 2=Only picto)
761
     * @param string $option On what the link point to
762
     * @param integer $notooltip 1=Disable tooltip
763
     * @param int $maxlen Max length of visible user name
764
     * @param string $morecss Add more css on link
765
     * @return string                      String with URL
766
     */
767
    public function getNomUrl($withpicto = 0, $option = '', $notooltip = 0, $maxlen = 24, $morecss = '')
768
    {
769
        global $langs, $conf, $db;
770
        global $dolibarr_main_authentication, $dolibarr_main_demo;
771
        global $menumanager;
772
773
        $result = '';
774
775
        $label = '<u>' . $langs->trans("Page") . '</u>';
776
        $label .= '<br>';
777
        $label .= '<b>' . $langs->trans('Ref') . ':</b> ' . $this->ref . '<br>';
778
        $label .= '<b>' . $langs->trans('ID') . ':</b> ' . $this->id . '<br>';
779
        $label .= '<b>' . $langs->trans('Title') . ':</b> ' . $this->title . '<br>';
780
        $label .= '<b>' . $langs->trans('Language') . ':</b> ' . $this->lang;
781
782
        $url = constant('BASE_URL') . '/website/index.php?websiteid=' . $this->fk_website . '&pageid=' . $this->id;
783
784
        $linkclose = '';
785
        if (empty($notooltip)) {
786
            if (getDolGlobalString('MAIN_OPTIMIZEFORTEXTBROWSER')) {
787
                $label = $langs->trans("ShowMyObject");
788
                $linkclose .= ' alt="' . dol_escape_htmltag($label, 1) . '"';
789
            }
790
            $linkclose .= ' title="' . dol_escape_htmltag($label, 1) . '"';
791
            $linkclose .= ' class="classfortooltip' . ($morecss ? ' ' . $morecss : '') . '"';
792
        } else {
793
            $linkclose = ($morecss ? ' class="' . $morecss . '"' : '');
794
        }
795
796
        $linkstart = '<a href="' . $url . '"';
797
        $linkstart .= $linkclose . '>';
798
        $linkend = '</a>';
799
800
        //$linkstart = $linkend = '';
801
802
        $result .= $linkstart;
803
        if ($withpicto) {
804
            $result .= img_picto(($notooltip ? '' : $label), ($this->picto ? $this->picto : 'generic'), ($notooltip ? (($withpicto != 2) ? 'class="paddingright"' : '') : 'class="' . (($withpicto != 2) ? 'paddingright ' : '') . 'classfortooltip"'), 0, 0, $notooltip ? 0 : 1);
805
        }
806
        if ($withpicto != 2) {
807
            $result .= $this->ref;
808
        }
809
        $result .= $linkend;
810
811
        return $result;
812
    }
813
814
    /**
815
     *  Return the label of the status
816
     *
817
     * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
818
     * @return string                 Label of status
819
     */
820
    public function getLibStatut($mode = 0)
821
    {
822
        return $this->LibStatut($this->status, $mode);
823
    }
824
825
    // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps
826
827
    /**
828
     *  Return the label of a given status
829
     *
830
     * @param int $status Id status
831
     * @param int $mode 0=long label, 1=short label, 2=Picto + short label, 3=Picto, 4=Picto + long label, 5=Short label + Picto, 6=Long label + Picto
832
     * @return string                 Label of status
833
     */
834
    public function LibStatut($status, $mode = 0)
835
    {
836
        // phpcs:enable
837
        global $langs;
838
839
        if (empty($this->labelStatus) || empty($this->labelStatusShort)) {
840
            global $langs;
841
            //$langs->load("mymodule");
842
            $this->labelStatus[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Offline');
843
            $this->labelStatus[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Online');
844
            $this->labelStatusShort[self::STATUS_DRAFT] = $langs->transnoentitiesnoconv('Offline');
845
            $this->labelStatusShort[self::STATUS_VALIDATED] = $langs->transnoentitiesnoconv('Online');
846
        }
847
848
        $statusType = 'status5';
849
        if ($status == self::STATUS_VALIDATED) {
850
            $statusType = 'status4';
851
        }
852
853
        return dolGetStatus($this->labelStatus[$status], $this->labelStatusShort[$status], '', $statusType, $mode);
854
    }
855
856
    /**
857
     * Sets object to given categories.
858
     *
859
     * Deletes object from existing categories not supplied.
860
     * Adds it to non existing supplied categories.
861
     * Existing categories are left untouch.
862
     *
863
     * @param int[]|int $categories Category ID or array of Categories IDs
864
     * @return  int                         Return integer <0 if KO, >0 if OK
865
     */
866
    public function setCategories($categories)
867
    {
868
        return $this->setCategoriesCommon($categories, Categorie::TYPE_WEBSITE_PAGE);
869
    }
870
871
    /**
872
     * Initialise object with example values
873
     * Id must be 0 if object instance is a specimen
874
     *
875
     * @return int
876
     */
877
    public function initAsSpecimen()
878
    {
879
        global $user;
880
881
        $this->id = 0;
882
883
        $now = dol_now();
884
885
        $this->fk_website = 0;
886
        $this->type_container = 'page';
887
        $this->pageurl = 'specimen';
888
        $this->aliasalt = 'specimenalt';
889
        $this->title = 'My Page';
890
        $this->description = 'This is my page';
891
        $this->image = '';
892
        $this->keywords = 'keyword1, keyword2';
893
        $this->allowed_in_frames = 1;
894
        $this->htmlheader = '';
895
        $this->content = '<html><body>This is a html content</body></html>';
896
        $this->status = self::STATUS_DRAFT;
897
        $this->grabbed_from = '';
898
        $this->date_creation = $now - (24 * 30 * 3600);
899
        $this->date_modification = $now - (24 * 7 * 3600);
900
        $this->fk_user_creat = $user->id;
901
        $this->author_alias = 'mypublicpseudo';
902
903
        return 1;
904
    }
905
}
906