diff --git a/js/lib/models/Discussion.js b/js/lib/models/Discussion.js index 2bb4cfdb9..bfecc00d0 100644 --- a/js/lib/models/Discussion.js +++ b/js/lib/models/Discussion.js @@ -2,14 +2,13 @@ import Model from 'flarum/Model'; import mixin from 'flarum/utils/mixin'; import computed from 'flarum/utils/computed'; import ItemList from 'flarum/utils/ItemList'; -import { slug } from 'flarum/utils/string'; import Badge from 'flarum/components/Badge'; export default class Discussion extends Model {} Object.assign(Discussion.prototype, { title: Model.attribute('title'), - slug: computed('title', slug), + slug: Model.attribute('slug'), startTime: Model.attribute('startTime', Model.transformDate), startUser: Model.hasOne('startUser'), diff --git a/migrations/2016_02_04_095452_add_slug_to_discussions.php b/migrations/2016_02_04_095452_add_slug_to_discussions.php new file mode 100644 index 000000000..27efa47e1 --- /dev/null +++ b/migrations/2016_02_04_095452_add_slug_to_discussions.php @@ -0,0 +1,41 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Core\Migration; + +use Flarum\Core\Discussion; +use Flarum\Database\AbstractMigration; +use Flarum\Util\Str; +use Illuminate\Database\Schema\Blueprint; + +class AddSlugToDiscussions extends AbstractMigration +{ + public function up() + { + $this->schema->table('discussions', function (Blueprint $table) { + $table->string('slug'); + }); + + // Store slugs for existing discussions + Discussion::chunk(100, function ($discussions) { + foreach ($discussions as $discussion) { + $discussion->slug = Str::slug($discussion->title); + $discussion->save(); + } + }); + } + + public function down() + { + $this->schema->table('discussions', function (Blueprint $table) { + $table->dropColumn('slug'); + }); + } +} diff --git a/src/Api/Serializer/DiscussionBasicSerializer.php b/src/Api/Serializer/DiscussionBasicSerializer.php index 52ca0e191..3a3ed157e 100644 --- a/src/Api/Serializer/DiscussionBasicSerializer.php +++ b/src/Api/Serializer/DiscussionBasicSerializer.php @@ -34,7 +34,8 @@ class DiscussionBasicSerializer extends AbstractSerializer } return [ - 'title' => $discussion->title + 'title' => $discussion->title, + 'slug' => $discussion->slug, ]; } diff --git a/src/Core/Discussion.php b/src/Core/Discussion.php index dd43ee370..8b6942719 100644 --- a/src/Core/Discussion.php +++ b/src/Core/Discussion.php @@ -22,10 +22,12 @@ use Flarum\Event\DiscussionWasRestored; use Flarum\Event\DiscussionWasStarted; use Flarum\Event\PostWasDeleted; use Flarum\Event\ScopePostVisibility; +use Flarum\Util\Str; /** * @property int $id * @property string $title + * @property string $slug * @property int $comments_count * @property int $participants_count * @property int $number_index @@ -432,4 +434,17 @@ class Discussion extends AbstractModel { static::$stateUser = $user; } + + /** + * Set the discussion title. + * + * This automatically creates a matching slug for the discussion. + * + * @param string $title + */ + protected function setTitleAttribute($title) + { + $this->attributes['title'] = $title; + $this->slug = Str::slug($title); + } } diff --git a/src/Util/Str.php b/src/Util/Str.php new file mode 100644 index 000000000..46e010a96 --- /dev/null +++ b/src/Util/Str.php @@ -0,0 +1,32 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Flarum\Util; + +class Str +{ + /** + * Create a slug out of the given string. + * + * Non-alphanumeric characters are converted to hyphens. + * + * @param string $str + * @return string + */ + public static function slug($str) + { + $str = strtolower($str); + $str = preg_replace('/[^a-z0-9]/i', '-', $str); + $str = preg_replace('/-+/', '-', $str); + $str = preg_replace('/-$|^-/', '', $str); + + return $str ?: '-'; + } +}