Project-Flyer-16-Service-Classes-and-Alternative-Approaches

跟随 Jeffrey Way 的视频学习,脑子不好,一些细节容易忘记,这里记录下来。相关视频在 laracasts.com
课程名称:Build “ProjectFlyer” With Me(16)

我们注意到,如果在首页,你没有登录也会显示 create 按钮,更科学的应该是没有登录显示注册按钮,登录成功显示创建按钮,现在我们来实现它。
想要知道如何判断是否登录,可以打开 Controller.php,可以看到:

view()->share('signedIn', Auth::check());

可以用这个语句判断:@if($signedIn)
我们修改 home.blade.php,我和作者的风格略有不同,更丰富些,将:

<p><a href="/flyers/create" class="btn btn-primary btn-lg" href="#" role="button">Create a Flyer</a></p>

改成:

@if($signedIn)
<p><a href="/flyers/create" class="btn btn-primary btn-lg" href="#" role="button">Create a Flyer</a></p>
@else
<p>
<a href="/auth/register" class="btn btn-danger btn-lg" href="#" role="button">Sign Up</a>
<a href="/auth/login" class="btn btn-success btn-lg" href="#" role="button">Sign In</a>
</p>
@endif

刷新可以看到效果,然后我们修改 FlyersController 控制器。
修改store方法里的:

Flyer::create($request->all());

为:

$this->user->publish(
new Flyer($request->all())
);

这个 publish 方法不存在,我们去 User.php 模型里创建它:

public function publish(Flyer $flyer)
{
$this->flyers()->save($flyer);
}

public function flyers()
{
return $this->hasMany(Flyer::class);
}

回到 FlyersController 控制器,store 方法的返回是back(),更科学的应该是返回我们刚创建的信息内容页才对,我们现在修改 store 方法的返回值。
修改:

return redirect()->back();

为:

return redirect($flyer->zip . '/' . str_replace(' ', '-', $flyer->address));

这种返回方式显然不美好,我们完善它。打开 Flyer.php 模型,添加 path()方法:

public function path()
{
return $this->zip . '/' . str_replace(' ', '-', $this->address);
}

现在可以把 store 的返回值:

return redirect($flyer->zip . '/' . str_replace(' ', '-', $flyer->address));

改成:

return redirect($flyer->path());

但更推荐的返回值是:

return redirect(flyer_path($flyer));

我们实现它。
通过根目录下的 composer.json 文件,我们可以看到 autoload 下的:

"files":[
"app/helpers.php"
],

我们打开 app/helpers.php,添加新方法flyer_path:

/**
* The Path to a given flyer
* @param App\Flyer $flyer
* @return string
*/
function flyer_path(App\Flyer $flyer)
{
return $flyer->zip . '/' . str_replace(' ', '-', $flyer->street);
}

删除刚添加的 Flyer.php 模型里的 path() 方法。修改 User.php 模型里

$this->flyers()->save($flyer);

为:

return $this->flyers()->save($flyer);

修改 FlyersController 控制器里的 store 方法里:

return redirect($flyer->path());

为:

return redirect(flyer_path($flyer));

现在刷新试试添加一条新数据,报错是:

FlyersController.php line 54:
Undefined variable: flyer

我们修改 FlyersController 里的 store 方法:

$this->user->publish(
new Flyer($request->all())
);

为:

$flyer = $this->user->publish(
new Flyer($request->all())
);

现在可以正常添加数据和照片了,但是我们发现,如果一次上传多个图片的时候会有在同一时间的图片出现图片无法显示的问题。应该是我们的图片重命名和时间有关:
filename()方法里的time()调用。
我们去路由器重新设定下路由,把照片添加的控制抽象出来。打开 routes.php,修改:

Route::post('{zip}/{street}/photos', ['as' => 'store_photo_path', 'uses' => 'FlyersController@addPhoto']);

为:

Route::post('{zip}/{street}/photos', ['as' => 'store_photo_path', 'uses' => 'PhotosController@store']);

然后去 homestead 网站根目录下运行命令创建 PhotosController 控制器:

php artisan make:controller PhotosController --plain

剪切 FlyersController 控制器里的:

/**
* Apply a photo to the referenced flyer
* @param string $zip
* @param string $street
* @param AddPhotoRequest $request
*/
public function addPhoto($zip, $street, AddPhotoRequest $request)
{
$photo = Photo::fromFile($request->file('photo'));

// $photo = $this->makePhoto($request->file('photo'));

Flyer::locatedAt($zip, $street)->addPhoto($photo);
}


PhotosController 控制器,然后修改方法名 AddPhoto 为 store。

打开 FlyerController,剪切:

use App\Http\Requests\AddPhotoRequest;

粘贴到 PhotosController 控制器,并在该控制器添加下面的引用:

use App\Flyer;
use App\Photo;

删除 FlyerController 控制器里的多余引用:

use App\Photo;

修改 PhotosController 控制器里的 store 方法为:

/**
* Apply a photo to the referenced flyer
* @param string $zip
* @param string $street
* @param AddPhotoRequest $request
*/
public function store($zip, $street, AddPhotoRequest $request)
{
$flyer = Flyer::locatedAt($zip, $street);
$photo = $request->file('photo');

(new AddPhotoToFlyer($flyer, $photo))->save();

}

注意到 AddPhotoToFlyer 类还不存在,我们创建它到:app\AddPhotoToFlyer.php,其内容如下:

<?php

namespace App;

use Symfony\Component\HttpFoundation\File\UploadedFile;

class AddPhotoToFlyer
{
protected $flyer;
protected $file;

public function __construct(Flyer $flyer, UploadedFile $file)
{
$this->flyer = $flyer;
$this->file = $file;
}

public function save()
{
// Attach the photo to the flyer
// move the photo to the images folder
// generate a thumbnail
}

}

然后在类里添加两个方法:

protected function makePhoto()
{
return new Photo(['name' => $this->makeFileName()]);
}

protected function makeFileName()
{

}

剪切 Photo.php 里的fileName()方法里的内容到 makeFileName()为:

protected function makeFileName()
{
$name = sha1(
time() . $this->file->getClientOriginalName()
);

$extension = $this->file->getClientOriginalExtension();

return "{$name}.{$extension}";
}

删除 Photo.php 里的 fileName() 方法。
在 Photo.php 里添加方法:

public function setNameAttribute($name)
{
$this->attributes['name'] = $name;

$this->path = $this->baseDir() . '/' . $name;
$this->thumbnail_path = $this->baseDir() . '/tn-' . $name;
}

删除 Photo.php 里的 filePath() 方法, thumbnailPath() 方法, fromFile() 方法, boot() 方法, makeThumbnail() 方法和 upload() 方法。
删除 Photo.php 里的 use Image;引用。
在 AddPhotoToFlyer.php 里添加use Image;引用。
修改 AddPhotoToFlyer 里的 save() 方法为:

public function save()
{
$photo = $this->flyer->addPhoto($this->makePhoto());

$this->file->move($photo->baseDir(), $photo->name);

$this->thumbnail->make($photo->path, $photo->thumbnail_path);
}

修改 AddPhotoFlyer.php 的构造方法为:

public function __construct(Flyer $flyer, UploadedFile $file, Thumbnail $thumbnail = null)
{
$this->flyer = $flyer;
$this->file = $file;
$this->thumbnail = $thumbnail ?: new Thumbnail;
}

注意到Thumbnail类是不存在的,我们现在创建它到:app/Thumbnail.php:
代码为:

<?php

namespace App;

use Image;

class Thumbnail
{
public function make($src, $destination)
{
Image::make($src)
->fit(200)
->save($destination);
}
}

删除 PhotoController 里多余的引用,最终的引用是:

use App\Flyer;
use App\AddPhotoToFlyer;
use App\Http\Controllers\Controller;
use App\Http\Requests\AddPhotoRequest;

测试下,一切 OK!

本节完!

0%