Dan Brown

Enabled utf8 slugs

Prevents slug change when using only non-ascii chars
Allows use of more localised urls.

Closes #233
...@@ -13,9 +13,9 @@ class Book extends Entity ...@@ -13,9 +13,9 @@ class Book extends Entity
13 public function getUrl($path = false) 13 public function getUrl($path = false)
14 { 14 {
15 if ($path !== false) { 15 if ($path !== false) {
16 - return baseUrl('/books/' . $this->slug . '/' . trim($path, '/')); 16 + return baseUrl('/books/' . urlencode($this->slug) . '/' . trim($path, '/'));
17 } 17 }
18 - return baseUrl('/books/' . $this->slug); 18 + return baseUrl('/books/' . urlencode($this->slug));
19 } 19 }
20 20
21 /* 21 /*
......
...@@ -32,9 +32,9 @@ class Chapter extends Entity ...@@ -32,9 +32,9 @@ class Chapter extends Entity
32 { 32 {
33 $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; 33 $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug;
34 if ($path !== false) { 34 if ($path !== false) {
35 - return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug . '/' . trim($path, '/')); 35 + return baseUrl('/books/' . urlencode($bookSlug) . '/chapter/' . urlencode($this->slug) . '/' . trim($path, '/'));
36 } 36 }
37 - return baseUrl('/books/' . $bookSlug. '/chapter/' . $this->slug); 37 + return baseUrl('/books/' . urlencode($bookSlug) . '/chapter/' . urlencode($this->slug));
38 } 38 }
39 39
40 /** 40 /**
......
...@@ -115,8 +115,10 @@ class ChapterController extends Controller ...@@ -115,8 +115,10 @@ class ChapterController extends Controller
115 $book = $this->bookRepo->getBySlug($bookSlug); 115 $book = $this->bookRepo->getBySlug($bookSlug);
116 $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id); 116 $chapter = $this->chapterRepo->getBySlug($chapterSlug, $book->id);
117 $this->checkOwnablePermission('chapter-update', $chapter); 117 $this->checkOwnablePermission('chapter-update', $chapter);
118 + if ($chapter->name !== $request->get('name')) {
119 + $chapter->slug = $this->chapterRepo->findSuitableSlug($request->get('name'), $book->id, $chapter->id);
120 + }
118 $chapter->fill($request->all()); 121 $chapter->fill($request->all());
119 - $chapter->slug = $this->chapterRepo->findSuitableSlug($chapter->name, $book->id, $chapter->id);
120 $chapter->updated_by = user()->id; 122 $chapter->updated_by = user()->id;
121 $chapter->save(); 123 $chapter->save();
122 Activity::add($chapter, 'chapter_update', $book->id); 124 Activity::add($chapter, 'chapter_update', $book->id);
......
...@@ -72,13 +72,13 @@ class Page extends Entity ...@@ -72,13 +72,13 @@ class Page extends Entity
72 { 72 {
73 $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug; 73 $bookSlug = $this->getAttribute('bookSlug') ? $this->getAttribute('bookSlug') : $this->book->slug;
74 $midText = $this->draft ? '/draft/' : '/page/'; 74 $midText = $this->draft ? '/draft/' : '/page/';
75 - $idComponent = $this->draft ? $this->id : $this->slug; 75 + $idComponent = $this->draft ? $this->id : urlencode($this->slug);
76 76
77 if ($path !== false) { 77 if ($path !== false) {
78 - return baseUrl('/books/' . $bookSlug . $midText . $idComponent . '/' . trim($path, '/')); 78 + return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent . '/' . trim($path, '/'));
79 } 79 }
80 80
81 - return baseUrl('/books/' . $bookSlug . $midText . $idComponent); 81 + return baseUrl('/books/' . urlencode($bookSlug) . $midText . $idComponent);
82 } 82 }
83 83
84 /** 84 /**
......
...@@ -147,8 +147,10 @@ class BookRepo extends EntityRepo ...@@ -147,8 +147,10 @@ class BookRepo extends EntityRepo
147 */ 147 */
148 public function updateFromInput(Book $book, $input) 148 public function updateFromInput(Book $book, $input)
149 { 149 {
150 + if ($book->name !== $input['name']) {
151 + $book->slug = $this->findSuitableSlug($input['name'], $book->id);
152 + }
150 $book->fill($input); 153 $book->fill($input);
151 - $book->slug = $this->findSuitableSlug($book->name, $book->id);
152 $book->updated_by = user()->id; 154 $book->updated_by = user()->id;
153 $book->save(); 155 $book->save();
154 $this->permissionService->buildJointPermissionsForEntity($book); 156 $this->permissionService->buildJointPermissionsForEntity($book);
...@@ -208,8 +210,7 @@ class BookRepo extends EntityRepo ...@@ -208,8 +210,7 @@ class BookRepo extends EntityRepo
208 */ 210 */
209 public function findSuitableSlug($name, $currentId = false) 211 public function findSuitableSlug($name, $currentId = false)
210 { 212 {
211 - $slug = Str::slug($name); 213 + $slug = $this->nameToSlug($name);
212 - if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
213 while ($this->doesSlugExist($slug, $currentId)) { 214 while ($this->doesSlugExist($slug, $currentId)) {
214 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); 215 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
215 } 216 }
......
...@@ -150,8 +150,7 @@ class ChapterRepo extends EntityRepo ...@@ -150,8 +150,7 @@ class ChapterRepo extends EntityRepo
150 */ 150 */
151 public function findSuitableSlug($name, $bookId, $currentId = false) 151 public function findSuitableSlug($name, $bookId, $currentId = false)
152 { 152 {
153 - $slug = Str::slug($name); 153 + $slug = $this->nameToSlug($name);
154 - if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
155 while ($this->doesSlugExist($slug, $bookId, $currentId)) { 154 while ($this->doesSlugExist($slug, $bookId, $currentId)) {
156 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); 155 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
157 } 156 }
......
...@@ -269,6 +269,19 @@ class EntityRepo ...@@ -269,6 +269,19 @@ class EntityRepo
269 $this->permissionService->buildJointPermissionsForEntities($collection); 269 $this->permissionService->buildJointPermissionsForEntities($collection);
270 } 270 }
271 271
272 + /**
273 + * Format a name as a url slug.
274 + * @param $name
275 + * @return string
276 + */
277 + protected function nameToSlug($name)
278 + {
279 + $slug = str_replace(' ', '-', strtolower($name));
280 + $slug = preg_replace('/[\+\/\\\?\@\}\{\.\,\=\[\]\#\&\!\*\'\;\:\$\%]/', '', $slug);
281 + if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
282 + return $slug;
283 + }
284 +
272 } 285 }
273 286
274 287
......
...@@ -614,8 +614,7 @@ class PageRepo extends EntityRepo ...@@ -614,8 +614,7 @@ class PageRepo extends EntityRepo
614 */ 614 */
615 public function findSuitableSlug($name, $bookId, $currentId = false) 615 public function findSuitableSlug($name, $bookId, $currentId = false)
616 { 616 {
617 - $slug = Str::slug($name); 617 + $slug = $this->nameToSlug($name);
618 - if ($slug === "") $slug = substr(md5(rand(1, 500)), 0, 5);
619 while ($this->doesSlugExist($slug, $bookId, $currentId)) { 618 while ($this->doesSlugExist($slug, $bookId, $currentId)) {
620 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3); 619 $slug .= '-' . substr(md5(rand(1, 500)), 0, 3);
621 } 620 }
......