Всем привет, кто читает мою статью. Продолжаем выполнение тестового задания. Выполним пункт 3-5. //3) Добавить возможность удалять статьи в мягком режиме
. При этом сделать возможность обновить систему со старой версии (из первого задания) на новую без полного сброса БД.// Для возможности удаление статей в мягком режиме из таблицы "articles" создадим миграцию : >php artisan make:migration ChangeArticleSoftTable --table=articles В созданной миграции в методе up() опишем softDeletes. %%(php) class ChangeArticleSoftTable extends Migration { public function up() { Schema::table('articles', function (Blueprint $table) { $table->softDeletes(); }); } ... } %% Применяем нашу миграцию. Внесем изменения в модель Article: добавим Trait SoftDeletes и добавим использование текущей метки времени для удаления. %%(php) class Article extends Model { ... use SoftDeletes; protected $dates=['deleted_at']; ... } %% Теперь при удалении статья не будет удаляться из БД. Статья остается в базе данных, но в БД устанавливается ее атрибут deleted_at. Если у статьи ненулевое значение deleted_at, значит статья мягко удалена. %%(php) class ArticleController extends SiteController { ... public function destroy(Article $article) { if (!Auth::user() || !$article->isAuthor(Auth::user())) { return abort('404'); } if ($article->delete()) { return redirect()->route('home')->with('status', __('articles.delete_success')); } return back()->withInput()->with([ 'status' => __('articles.warning') ]); } ... } %% Доработаем наш проект: реализуем окончательное удаление и восстановление статьи - соответственно. %%(php) class ArticleController extends SiteController { ... public function erase(Request $request, $article_id) { if (!Auth::user()) { return abort('404'); } $article_for_delete = Article::withTrashed()->find($article_id); $article_for_delete->users()->detach(); if ($article_for_delete->forceDelete()) { return redirect()->route('home')->with('status', __('articles.delete_end_success')); } return back()->withInput()->with('status', __('articles.warning')); } public function restore(Request $request, $article_id) { if (!Auth::user()) { return abort('404'); } $article_for_restore = Article::withTrashed()->find($article_id); if ($article_for_restore->restore()) { return redirect()->route('home')->with('status', __('articles.restore_success')); } return back()->withInput()->with('status', __('articles.warning')); } } %% Для получения списка статей в корзине: %%(php) class IndexController extends SiteController { ... public function trash() { $this->title = __('articles.title_trash'); $title = $this->title; $articles = Auth::user()->getArticlesTrash(); $auth_user = Auth::user(); $this->content = view('trash', compact('title', 'articles', 'auth_user'))->render(); return $this->renderOutput(); } ... } %% //4) Теперь надо создать функцию в классе статей, которая: принимает пользователя и только пользователя – выдаёт mismatch в противном случае, возвращает 
истину, если указанный человек автор статьи, 
ложь – если это не так – null если статья удалена. Если функция пытается вернуть что – то иное – mismatch.// Создадим функцию isAuthor: %%(php) class Article extends Model { ... public function isAuthor($user) { if (!$user) { return Config::get('constants.mismatch'); } if ($this->trashed()) { return null; } if ($this->users()->find($user->id)) { return true; } else { return false; } } ... } %% //5) ORM: Добавим новое поле пользователю user – experience 
Нужно создать функцию, в которой будет извлекаться пользователь и сохраняться в переменную $user = User::find(1). Дальше функция выводит experience. Параллельно с работой функции асинхронный метод меняет опыт на случайное число каждые несколько секунд. 
В первой функции ещё раз выводится спустя промежуток времени опыт пользователя. 
Каким будет этот вывод?// "С этим пунктом справился не до конца". Для начала создадим миграцию для добавления поля experience. >php artisan make:migration ChangeUserAddExperienceTable --table=users В созданной миграции в методе up() опишем создаваемое поле. %%(php) class ChangeUserAddExperienceTable extends Migration { public function up() { Schema::table('users', function (Blueprint $table) { $table->integer('experience')->unsigned()->default(1); }); } ... } %% Добавим методы для получения и изменения поля experience соответственно: %%(php) class UserController extends SiteController { ... public function getExperience(Request $request) { $getExprnc = $this->userService->getExperienceUser($request); if ($getExprnc) { return response()->json([ 'success'=>__('site.get_experience'), 'user_experience' => $getExprnc ]); } return response()->json([ 'status' => __('site.warning') ]); } ... } class UserService { ... public function getExperienceUser($request) { if (empty($request)) { return false; } return User::find($request->user_id)->experience; } ... } class UserController extends SiteController { ... public function setExperience(Request $request) { if ($this->userService->setExperienceUser($request)) { return response()->json([ 'success'=>__('site.set_experience') ]); } return response()->json([ 'status' => __('site.warning') ]); } ... } class UserService { ... public function setExperienceUser($request) { if (empty($request)) { return false; } $user = User::find($request->user_id); $user->experience = random_int(1, 50); if ($user->update()) { return true; } return false; } ... } %% Определим routes, которые понадобятся для выполнения методов: %%(php) Route::group(['middleware' => ['web']], function () { ... Route::group(['middleware' => ['auth']], function() { ... Route::post('/get_experience','UserController@getExperience'); Route::post('/set_experience','UserController@setExperience'); }); ... }); %% Для реализации задания написал скрипт, который использует ajax: %%(php) var startInterval; var count = 1; function get_experience() { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); $.ajax({ url: "/get_experience", type: "post", data: { user_id: $("#user_id").val() }, success: function(result){ //console.log(result); $("#experience").text(result['user_experience']); } }); }; function set_experience() { $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); $.ajax({ url: "/set_experience", type: "post", data: { user_id: $("#user_id").val() }, success: function(result){ //console.log(result); } }); }; function timerFired () { if((count % 2)==0){ get_experience(); } else { set_experience(); } count = count + 1; } $(document).ready(function() { $('#start_experience').click(function(e) { clearInterval(startInterval); startInterval = setInterval(timerFired,1000); }); $('#stop_experience').click(function(e) { clearInterval(startInterval); }); }); %% ((https://lh3.googleusercontent.com/XEcuH2fAsj-nldx4PndgQRCvNTe8eSfSCDWJiGwtV02gbK782wuyKa-HlDmGJU6GAiZXlab_cAN_K200VQOvzlvnDrQTXoRETGOQIf1c0dDxmtcewNKKbnHOnJo25_tjS7SHEsMT6HAFLkeoiIRlgML7GaqZ82ebuWtC_2dm38xTd6kifPeuPbgtFiH4kgIQU9NngkYGs67ssBD5gD1NEndbtcWutcRX7rKzzXgn1pPZVmXw6LDSpo9ApmN807pOBai_f0hCuE-N84VJ0xttyqepZOt1vWLqtpCj7n4IN9zoDXC_OmHTASm8lksFU6TvDUytchoTQQeht9OVqSQUhZOOZF5bZRG4QlRYi-_hGNZ-7F_ZBbkKneUgmSrrsZMbtukbSA1dkCiLMmjZqdZ1RdQBljykLz7RTMAq5mWS5GI_UXMeRLvE6Ftq2CctjSQ87x1teUOSgzG6Ney8_o0Giu4YeHSeZAsMHo-3SlZsqdPa10tXoLB-MIHCPYmu9yThU4zkrs6Y9Bq4gx6SWI_ESGKueAacALRbgOhrGFZhPSrUZvplJysUNcnrhvzqMjds-NnPq6EFqCs1WHEHw4erdx_vrtx5mjYfjM1WRZPekpfB80HvYb6dt6EBphMTdvs2yX0Rlr1KsKqh4smABhQajQB_pURTbckF1gmHSSYbXhT-=w861-h560-no Скрин)) Ссылка на ((https://github.com/vol-mir/larablog.test Git)).