Всем привет, кто читает мою статью.
Продолжаем выполнение тестового задания. Выполним пункт 3-5.
3) Добавить возможность удалять статьи в мягком режиме
. При этом сделать возможность обновить систему со старой версии (из первого задания) на новую без полного сброса БД.
Для возможности удаление статей в мягком режиме из таблицы «articles» создадим миграцию :
- php artisan make:migration ChangeArticleSoftTable --table=articles
В созданной миграции в методе up() опишем softDeletes.
class ChangeArticleSoftTable extends Migration
{
public function up()
{
Schema::table('articles', function (Blueprint $table) {
$table->softDeletes();
});
}
...
}
Применяем нашу миграцию. Внесем изменения в модель Article: добавим Trait SoftDeletes и добавим использование текущей метки времени для удаления.
class Article extends Model
{
...
use SoftDeletes;
protected $dates=['deleted_at'];
...
}
Теперь при удалении статья не будет удаляться из БД. Статья остается в базе данных, но в БД устанавливается ее атрибут deleted_at. Если у статьи ненулевое значение deleted_at, значит статья мягко удалена.
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')
]);
}
...
}
Доработаем наш проект: реализуем окончательное удаление и восстановление статьи — соответственно.
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'));
}
}
Для получения списка статей в корзине:
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:
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() опишем создаваемое поле.
class ChangeUserAddExperienceTable extends Migration
{
public function up()
{
Schema::table('users', function (Blueprint $table) {
$table->integer('experience')->unsigned()->default(1);
});
}
...
}
Добавим методы для получения и изменения поля experience соответственно:
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, которые понадобятся для выполнения методов:
Route::group(['middleware' => ['web']], function () {
...
Route::group(['middleware' => ['auth']], function() {
...
Route::post('/get_experience','UserController@getExperience');
Route::post('/set_experience','UserController@setExperience');
});
...
});
Для реализации задания написал скрипт, который использует ajax:
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);
});
});
Комментарии (8)
$data = [];
$data ['title'] = $this->title;
$data ['articles'] = $articles_trash_user;
$data ['auth_user'] = Auth::user();
почему не так?
$data = [
'title' ⇒ $this->title,
......
];
public function isAuthor($user) {
if ($user) {
if($this->trashed()) {
return null;
}
if ($this->users()->find($user->id)) {
return true;
} else {
return false;
}
}
return'mismatch';
}
чем меньше вложенность ифов, тем удобнее читать код, лучше так:
if (!user) {
return 'mismatch';
}
...тут остальное без вложенности
и еще — лучше все тексты по типу «mismatch» выносить куда-нибудь в константы
Отдельное спасибо, за такие комментарии) Возьму себе в заметки
Спасибо, исправил
Никогда не понимал смысл такой конструкции
Звучит как
Если true - вернуть true иначе вернуть false
. Сразу напрашивается более короткий вариантСпасибо за советы)
Спасибо, исправил
public function isAuthor(User $user)
{
return $this->users->contains($user);
}
Так еще проще.