1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* This file contains functionality relating to database objects that have a custom URL such as teams and players |
4
|
|
|
* |
5
|
|
|
* @package BZiON\Models |
6
|
|
|
* @license https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3 |
7
|
|
|
*/ |
8
|
|
|
|
9
|
|
|
/** |
10
|
|
|
* A Model that has a URL and an alias |
11
|
|
|
* @package BZiON\Models |
12
|
|
|
*/ |
13
|
|
|
abstract class AliasModel extends UrlModel implements NamedModel |
14
|
|
|
{ |
15
|
|
|
/** |
16
|
|
|
* The name of the object |
17
|
|
|
* @var string |
18
|
|
|
*/ |
19
|
|
|
protected $name; |
20
|
|
|
|
21
|
|
|
/** |
22
|
|
|
* A unique URL-friendly identifier for the object |
23
|
|
|
* @var string |
24
|
|
|
*/ |
25
|
|
|
protected $alias; |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Get the name of the object |
29
|
|
|
* @return string |
30
|
|
|
*/ |
31
|
39 |
|
public function getName() |
32
|
|
|
{ |
33
|
39 |
|
return $this->name; |
34
|
|
|
} |
35
|
|
|
|
36
|
|
|
/** |
37
|
|
|
* Get the name of the team, safe for use in your HTML |
38
|
|
|
* |
39
|
|
|
* @return string The name of the team |
40
|
|
|
*/ |
41
|
1 |
|
public function getEscapedName() |
42
|
|
|
{ |
43
|
1 |
|
if (!$this->valid) { |
44
|
|
|
return "<em>None</em>"; |
45
|
|
|
} |
46
|
|
|
|
47
|
1 |
|
return $this->escape($this->name); |
48
|
|
|
} |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* Change the object's name |
52
|
|
|
* |
53
|
|
|
* @return self |
54
|
|
|
*/ |
55
|
|
|
public function setName($name) |
56
|
|
|
{ |
57
|
|
|
$this->updateProperty($this->name, 'name', $name); |
58
|
|
|
$this->resetAlias(); |
59
|
|
|
|
60
|
|
|
return $this; |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* Get an object's alias |
65
|
|
|
* @return string|int The alias (or ID if the alias doesn't exist) |
66
|
|
|
*/ |
67
|
5 |
|
public function getAlias() |
68
|
|
|
{ |
69
|
5 |
|
if ($this->alias !== null && $this->alias != "") { |
70
|
4 |
|
return $this->alias; |
71
|
|
|
} |
72
|
|
|
|
73
|
1 |
|
return $this->getId(); |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Set a model's alias |
78
|
|
|
* @param string $alias The new alias |
79
|
|
|
* @return void |
80
|
|
|
*/ |
81
|
|
|
public function setAlias($alias) |
82
|
|
|
{ |
83
|
|
|
$this->updateProperty($this->alias, 'alias', $alias); |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Reset a model's alias based on its name |
88
|
|
|
* @return self |
89
|
|
|
*/ |
90
|
38 |
|
public function resetAlias() |
91
|
|
|
{ |
92
|
38 |
|
$alias = static::generateAlias($this->name, $this->id); |
93
|
|
|
|
94
|
38 |
|
return $this->updateProperty($this->alias, 'alias', $alias); |
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
/** |
98
|
|
|
* {@inheritdoc} |
99
|
|
|
*/ |
100
|
1 |
|
public function getURL($action = 'show', $absolute = false, $params = array()) |
101
|
|
|
{ |
102
|
1 |
|
if (!$this->isValid()) { |
103
|
|
|
return ""; |
104
|
|
|
} |
105
|
|
|
|
106
|
1 |
|
if (in_array(strtolower($action), array('edit', 'delete', 'kick', 'invite', 'change-leader'))) { |
107
|
|
|
// Make sure we provide the correct link for dangerous actions, even |
108
|
|
|
// if the model changes its name |
109
|
1 |
|
$alias = $this->getId(); |
110
|
|
|
} else { |
111
|
1 |
|
$alias = $this->getAlias(); |
112
|
|
|
} |
113
|
|
|
|
114
|
1 |
|
return $this->getLink($alias, $action, $absolute, $params); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* Gets an entity from the supplied alias |
119
|
|
|
* @param string $alias The object's alias |
120
|
|
|
* @return AliasModel |
121
|
|
|
*/ |
122
|
3 |
|
public static function fetchFromAlias($alias) |
123
|
|
|
{ |
124
|
3 |
|
return static::get(self::fetchIdFrom($alias, "alias")); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* {@inheritdoc} |
129
|
|
|
* @return AliasModel |
130
|
|
|
*/ |
131
|
3 |
|
public static function fetchFromSlug($slug) |
132
|
|
|
{ |
133
|
3 |
|
if (ctype_digit((string) $slug)) { |
134
|
|
|
// Slug is an integer, we can fetch by ID |
135
|
2 |
|
return static::get((int) $slug); |
136
|
|
|
} else { |
137
|
|
|
// Slug is something else, we can fetch by alias |
138
|
2 |
|
return self::fetchFromAlias($slug); |
139
|
|
|
} |
140
|
|
|
} |
141
|
|
|
|
142
|
|
|
/** |
143
|
|
|
* Generate a URL-friendly unique alias for an object name |
144
|
|
|
* |
145
|
|
|
* @param string $name The original object name |
146
|
|
|
* @param int|null $id The ID of the object, if it's being edited and not created |
147
|
|
|
* @return string|null The generated alias, or Null if we couldn't make one |
148
|
|
|
*/ |
149
|
39 |
|
public static function generateAlias($name, $id = null) |
150
|
|
|
{ |
151
|
|
|
// Convert name to lowercase |
152
|
39 |
|
$name = strtolower($name); |
153
|
|
|
|
154
|
|
|
// List of characters which should be converted to dashes |
155
|
39 |
|
$makeDash = array(' ', '_'); |
156
|
|
|
|
157
|
39 |
|
$name = str_replace($makeDash, '-', $name); |
158
|
|
|
|
159
|
|
|
// Only keep letters, numbers and dashes - delete everything else |
160
|
39 |
|
$name = preg_replace("/[^a-zA-Z\-0-9]+/", "", $name); |
161
|
|
|
|
162
|
39 |
|
if (str_replace('-', '', $name) == '') { |
163
|
|
|
// The name only contains symbols or Unicode characters! |
164
|
|
|
// This means we can't convert it to an alias |
165
|
1 |
|
return null; |
166
|
|
|
} |
167
|
|
|
|
168
|
|
|
// An alias name can't only contain numbers, because it will be |
169
|
|
|
// indistinguishable from an ID. If it does, add a dash in the end. |
170
|
|
|
// Also prevent aliases from taking names such as "new", |
171
|
39 |
|
while (preg_match("/^[0-9]+$/", $name)) { |
172
|
1 |
|
$name = $name . '-'; |
173
|
|
|
} |
174
|
|
|
|
175
|
39 |
|
return self::getUniqueAlias($name, ($id) ?: 0); |
176
|
|
|
} |
177
|
|
|
|
178
|
|
|
/** |
179
|
|
|
* Make sure that the generated alias provided is unique |
180
|
|
|
* |
181
|
|
|
* @param string $alias The alias |
182
|
|
|
* @param int $id The ID of the object, if it's being edited and not created |
183
|
|
|
* @return string An alias that is guaranteed to be unique |
184
|
|
|
*/ |
185
|
39 |
|
private static function getUniqueAlias($alias, $id = 0) |
186
|
|
|
{ |
187
|
|
|
// Try to find duplicates |
188
|
39 |
|
$db = Database::getInstance(); |
189
|
39 |
|
$result = $db->query("SELECT alias FROM " . static::TABLE . " WHERE id != ? AND alias REGEXP ?", array($id, "^" . $alias . "[0-9]*$")); |
190
|
|
|
|
191
|
|
|
// Convert the multi-dimensional array that $db->query() gave us into |
192
|
|
|
// a single-dimensional one. |
193
|
39 |
|
$aliases = (is_array($result)) ? array_column($result, 'alias') : array(); |
194
|
|
|
|
195
|
|
|
// If there's already an entry with the alias we generated, put a number |
196
|
|
|
// in the end of it and keep incrementing it until there is we find |
197
|
|
|
// an open spot. |
198
|
39 |
|
$currentAlias = $alias; |
199
|
39 |
|
for ($i = 2;; ++$i) { |
200
|
39 |
|
if (!in_array($currentAlias, $aliases) |
201
|
39 |
|
&& !in_array($currentAlias, static::getDisallowedAliases())) { |
202
|
39 |
|
break; |
203
|
|
|
} |
204
|
|
|
|
205
|
26 |
|
$currentAlias = $alias . $i; |
206
|
|
|
} |
207
|
|
|
|
208
|
39 |
|
return $currentAlias; |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* Get a list of aliases that should not be given to objects |
213
|
|
|
* |
214
|
|
|
* For example, you want to prevent teams from getting the "new" alias. |
215
|
|
|
* Otherwise, the team's link would be http://example.com/bzion/teams/new, |
216
|
|
|
* and the user would go to the team creation page instead of the team's page. |
217
|
|
|
* Disallowed aliases will have a number appended, so the URL would be |
218
|
|
|
* http://example.com/bzion/teams/new2 |
219
|
|
|
* |
220
|
|
|
* @return string[] |
221
|
|
|
*/ |
222
|
39 |
|
protected static function getDisallowedAliases() |
223
|
|
|
{ |
224
|
39 |
|
return array('new'); |
225
|
|
|
} |
226
|
|
|
} |
227
|
|
|
|