火花思维
A while ago, I wrote about a product I wanted to build, to allow easy remote backups for Pagekit sites. I’ve been working on it (periodically) since then, and have come across a few interesting bits of advice.
不久前, 我写了一篇我想构建的产品 ,以便可以轻松地对Pagekit站点进行远程备份。 从那时起,我一直(定期)从事此工作,并且遇到了一些有趣的建议。
I decided to use Laravel Spark as the foundation for the product, and I thought it would be helpful to share the advice. Whether you’re just starting your Spark app, or are in maintenance mode, I think you’ll find some of these tips useful!
我决定将Laravel Spark用作产品的基础,我认为分享建议会有所帮助。 无论您是刚刚启动Spark应用程序,还是处于维护模式,我都认为您会发现其中一些有用的提示!
![Laravel Spark Website Splash Screen](https://dab1nmslvvntp.cloudfront.net/wp-content/uploads/2016/09/1475064054Screenshot-2016-09-28-14.00.26.png)
1.您不必保留所有基本文件 (1. You Don’t Have to Keep All the Base Files)
You may be worried about removing too many of the base files from the standard Spark installation. When I first started, I thought it vital not to change the auth controllers (in app/Http/Controllers/Auth
), for fear that it’d break the registration and login system.
您可能会担心从标准Spark安装中删除太多基本文件。 刚开始时,我认为不要更改auth控制器(在app/Http/Controllers/Auth
)至关重要,因为这会破坏注册和登录系统。
Turns out, these files aren’t used by Spark. In fact, if you add routes to them, and you try to register/log in, you’ll probably just encounter problems. These default auth controllers share the same auth guard (session driver), so logging in through one will make you authenticated through the other.
事实证明,Spark不使用这些文件。 实际上,如果向它们添加路由,然后尝试注册/登录,则可能会遇到问题。 这些默认的身份验证控制器共享相同的身份验证保护(会话驱动程序),因此通过一个登录即可使您通过另一个身份验证。
If, however, you try to register through the non-Spark controllers, your user and team accounts will be missing vital Spark information. It’s cleaner and simpler to just delete these auxiliary auth controllers.
但是,如果您尝试通过非Spark控制器注册,则您的用户和团队帐户将缺少重要的Spark信息。 删除这些辅助身份验证控制器会更干净,更简单。
If you’re unsure, make a full backup. Then you can roll back in case your tests pick up any regressions.
如果不确定,请进行完整备份 。 然后,您可以回滚以防您的测试出现任何回归。
2.使用简单的存储库 (2. Use Simple Repositories)
Spark includes a few simple repositories. These are like static config lists (for countries and other mostly-static data), but they can be loaded through the IoC container. They look like this:
Spark包含一些简单的存储库。 这些就像静态配置列表(用于国家和其他大多数静态数据)一样,但是它们可以通过IoC容器加载。 他们看起来像这样:
namespace Laravel\Spark\Repositories\Geography;
use Laravel\Spark\Contracts\Repositories\↩
Geography\CountryRepository as Contract;
class CountryRepository implements Contract
{
/**
* {@inheritdoc}
*/
public function all()
{
return [
'AF' => 'Afghanistan',
'AX' => 'Åland Islands',
'AL' => 'Albania',
// ...snip
'YE' => 'Yemen',
'ZM' => 'Zambia',
'ZW' => 'Zimbabwe',
];
}
}
This is from vendor/bin/laravel/spark/src/Repositories/Geography/CountryRepository.php
这是来自vendor/bin/laravel/spark/src/Repositories/Geography/CountryRepository.php
We can see instances of this being used in some of the registration views:
我们可以在某些注册视图中看到此实例:
<select class="form-control" v-model="registerForm.country"↩
lazy>
@foreach (app(Laravel\Spark\Repositories\↩
Geography\CountryRepository::class)->all()↩
as $key => $country)
<option value="{{ $key }}">{{ $country }}</option>
@endforeach
</select>
This is from resources/views/vendor/spark/auth/register-address.blade.php
这是从resources/views/vendor/spark/auth/register-address.blade.php
I highly recommend you use these repositories for country and state data. I also recommend you use this repository style for your own lists:
我强烈建议您将这些存储库用于国家和州数据。 我还建议您对自己的列表使用此存储库样式:
namespace App\Repositories;
use DateTimeZone;
class TimezoneRepository
{
/**
* @return array
*/
public function get()
{
$identifiers = DateTimeZone::listIdentifiers(DateTimeZone::ALL);
return array_combine(
$identifiers,
array_map(function ($identifier) {
return str_replace("_", " ", $identifier);
}, $identifiers)
);
}
}
You don’t have to make an interface for each repository. In fact, I think that’s a bit of an overkill. But I think these tiny repositories are much cleaner and easier to use than the alternatives.
您不必为每个存储库都建立一个接口。 实际上,我认为这有点过头了。 但是我认为这些小型存储库比其他存储库更清洁,更易于使用。
In addition, you can alias these in an application service provider:
此外,您可以在应用程序服务提供者中为它们加上别名:
namespace App\Providers;
use App\Repositories\CountryRepository;
use App\Repositories\TimezoneRepository;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* @inheritdoc
*/
public function register()
{
$this->app->singleton("timezones", function () {
return new TimezoneRepository();
});
}
}
This is from app/Providers/AppServiceProvider.php
这来自app/Providers/AppServiceProvider.php
This makes them super easy to use in views:
这使它们在视图中超级易于使用:
<select class="form-control" v-model="registerForm.timezone"↩
lazy>
@foreach (app("timezones")->get() as $key => $timezone)
<option value="{{ $key }}">{{ $timezone }}</option>
@endforeach
</select>
In general, you should try to use existing lists of data. When you absolutely have to maintain your own, I’ve found this strategy works well.
通常,您应该尝试使用现有数据列表。 当您绝对需要维护自己的时,我发现此策略很好用。
3.不要使用插入号(^)Laravel依赖项 (3. Don’t use caret (^) Laravel dependencies)
Laravel evolves rapidly. That’s great for keeping developers interested, but it has maintenance drawbacks. Do yourself a favor and replace any ^x.x
dependency version numbers with ~x.x.x
version numbers.
Laravel发展Swift。 这对于使开发人员保持兴趣非常有用,但是它具有维护方面的缺陷。 请你帮个忙,并更换^xx
与依赖的版本号~xxx
的版本号。
Spark 1.x
is built with Laravel 5.2.x
. If you’re not careful (read: using ^5.2
), a call to composer update
will upgrade Laravel to 5.3.x
, which introduces many breaking changes.
Spark 1.x
是使用Laravel 5.2.x
构建的。 如果您不小心(请参阅:使用^5.2
),则调用composer update
会将Laravel升级到5.3.x
,这将带来许多重大更改。
Laravel does not claim to follow Semver, so there’s no reason to assume minor version bumps will be safe. That said, Taylor is quite reasonable when it comes to the difficulty involved in upgrading minor versions. If the breaking changes introduced take too long to mitigate, they’ll be held back until the next major version.
Laravel并未声称会遵循Semver,因此没有理由认为次要版本的安全性是安全的。 也就是说,泰勒在升级次要版本时遇到的困难是非常合理的。 如果引入的重大更改花费的时间太长而无法缓解,则将这些更改保留到下一个主要版本。
Spark 2.x
is based on Laravel 5.3.x
, so start there if you can. Then you’ll have access to all the shiny new features in 5.3.x
from the get-go. It’s much easier to start a new Spark application than it is to upgrade an existing one. Trust me on that…
Spark 2.x
基于Laravel 5.3.x
,因此,如果可以的话,从那里开始。 然后,您可以从一开始就访问5.3.x
所有闪亮的新功能。 启动新的Spark应用程序比升级现有的应用程序容易得多。 相信我……
Once again, you’re better off making a full backup before running composer update
. You’re building a product. You’ve paid money to use Spark. Backups are now a thing.
再一次,最好在运行composer update
之前进行完整备份。 您正在构建产品。 您已经支付了使用Spark的费用。 现在备份已成问题。
4.文档是您的朋友 (4. The Docs Are Your Friend)
There’s a lot of assumed knowledge bundled into Spark. Most of the bundled views use (or at least reference) VueJS components. Spark depends on Cashier and either Stripe or Braintree.
Spark中捆绑了许多假定的知识。 大多数捆绑视图使用(或至少参考)VueJS组件。 Spark取决于Cashier以及Stripe或Braintree 。
You don’t need to be an expert on these things, but if you need to touch any of them, don’t try and do it without first going through the related documentation. Or all the documentation.
您不需要成为这些方面的专家,但是,如果您需要触摸其中的任何一个,请不要先尝试阅读相关文档,然后再尝试做。 或所有文档。
I found sections like “Adding registration fields” particularly useful, because they cover the full range of edits required to make a change.
我发现“添加注册字段”等部分特别有用,因为它们涵盖了进行更改所需的全部编辑范围。
Take a look at the free Laracasts videos as well. They’re a bit dated now, but still a good source of knowledge.
还可以观看免费的Laracasts视频 。 他们现在有些过时了,但仍然是很好的知识来源。
5.不要感到学习VueJS的压力 (5. Don’t Feel Pressured to Learn VueJS)
I know I just mentioned VueJS, but the truth is that you don’t really need to learn it before trying Spark. Before I spent a lot of time in Spark, I thought that I did. Turns out the docs tell you all you need to know, and the bundled views fill any gaps with examples.
我知道我刚刚提到过VueJS,但事实是您在尝试Spark之前并不需要真正学习它。 在花很多时间在Spark之前,我以为自己做了。 事实证明,文档会告诉您所有您需要了解的内容,并且捆绑的视图填补了示例中的空白。
If your goal is to do some swish-bang front-end stuff, it’s not a bad idea to learn VueJS. If all you need (JabbaScript-wise) is to add a field here or there, just follow the examples in code.
如果您的目标是做一些前卫的前端工作,那么学习VueJS并不是一个坏主意。 如果只需要在JabbaScript处添加一个字段,则只需遵循代码中的示例即可。
There’s nothing stopping you from making all your app-specific code plain ol’ HTML and PHP.
没有什么能阻止您将所有特定于应用程序的代码制成HTML和PHP。
6.在Forge上托管 (6. Host on Forge)
Sincerely (and without any encouragement to mention them), I cannot recommend Forge highly enough. It’s sensible, affordable server management, geared towards Laravel applications.
真诚的(并且不鼓励他们提及它们),我不能高度推荐Forge 。 它是面向Laravel应用程序的明智,价格合理的服务器管理。
I’ve hosted other (non-Spark) things there, but it has made my Spark experience richer. I’ve particularly enjoyed the .env
, scheduler and queued job daemon management tools. Every subscription-based app needs scheduled jobs. Every moderately complex application benefits from queued jobs.
我在这里托管了其他(非火花)设备,但是这使我的Spark体验更加丰富。 我特别喜欢.env
,调度程序和排队的作业守护程序管理工具。 每个基于订阅的应用都需要计划的作业。 每个中等复杂的应用程序都将从排队的作业中受益。
7.重新安排中间件 (7. Re-Arrange Middleware)
One of the best features (in my personal opinion) of Laravel is route model binding. That’s when you define routes like this:
Laravel的最佳功能之一(以我个人观点)是路由模型绑定 。 就是在这样定义路由时:
use App\Http\Controllers\CustomersController;
Route::get("customers/:customer", [
"uses" => CustomersController::class,
"as" => "customers.edit",
]);
…and then define that action as:
…然后将该动作定义为:
/**
* @param Customer $customer
*
* @return Response
*/
public function edit(Customer $customer)
{
return view("customers.edit", [
"customer" => $customer,
"groups" => Groups::all(),
]);
}
If you run this code (as a controller action), $customer
will automatically be pulled from the database. It’s a powerful feature! When I started this Spark 1.x
application, I was careful to apply global scopes to all team-specific models:
如果运行此代码(作为控制器操作),则$customer
将自动从数据库中拉出。 这是一个强大的功能! 启动此Spark 1.x
应用程序时,我小心地将全局范围应用于所有特定于团队的模型:
namespace App\Scopes;
use App\User;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Scope;
class TeamScope implements Scope
{
/**
* @param Builder $builder
* @param Model $model
*
* @return Builder
*/
public function apply(Builder $builder, Model $model)
{
/** @var User $user */
$user = auth()->user();
return $builder->where(
"team_id", "=", $user->currentTeam()->id
);
}
}
This is from app/Scopes/TeamScope.php
这来自app/Scopes/TeamScope.php
I applied this in the models’ boot()
methods:
我在模型的boot()
方法中应用了此方法:
namespace App;
use App\Scopes\TeamScope;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
/**
* @inheritdoc
*/
protected static function boot()
{
parent::boot();
static::addGlobalScope(new TeamScope());
}
}
The expected behavior would be that all customers are then filtered according to logged-in users’ current teams. The trouble is that this doesn’t work in 5.2.x
, as the session isn’t started when route model bindings happen. To get around this, I had to move the session middleware out of the web
group and into the global group:
预期的行为是,然后根据登录用户的当前团队对所有客户进行筛选。 问题在于这在5.2.x
不起作用,因为在发生路由模型绑定时会话没有启动。 为了解决这个问题,我必须将会话中间件移出web
组并移至全局组:
/**
* The application's global HTTP middleware stack.
*
* These middleware are run during every request to your application.
*
* @var array
*/
protected $middleware = [
\Illuminate\Foundation\Http\Middleware\CheckForMaintenanceMode::class,
\Illuminate\Session\Middleware\StartSession::class
];
/**
* The application's route middleware groups.
*
* @var array
*/
protected $middlewareGroups = [
'web' => [
\App\Http\Middleware\EncryptCookies::class,
\Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
// \Illuminate\Session\Middleware\StartSession::class,
\Illuminate\View\Middleware\ShareErrorsFromSession::class,
\App\Http\Middleware\VerifyCsrfToken::class,
],
'api' => [
'throttle:60,1',
],
];
This is from app/Http/Kernel.php
这是来自app/Http/Kernel.php
Notice how I’ve commented out \Illuminate\Session\Middleware\StartSession::class
in $middlewareGroups["web"]
, and added it to $middleware
? Doing that starts the session before Model::boot()
, which means auth()->user()
(or Auth::user()
) will then return the logged-in user.
注意我如何注释掉$middlewareGroups["web"]
\Illuminate\Session\Middleware\StartSession::class
,并将其添加到$middleware
? 这样做会在Model::boot()
之前启动会话,这意味着auth()->user()
(或Auth::user()
)将返回登录用户。
8.自己做帮手 (8. Make Your Own Helpers)
I cannot tell you how many times I used the following code:
我无法告诉您使用以下代码多少次:
/** @var User $user */
$user = auth()->user();
/** @var Team $team */
$team = user()->currentTeam();
…before I created these helpers:
…在创建这些帮助器之前:
use App\User;
use App\Team;
if (!function_exists("user")) {
/**
* @return App\User
*/
function user() {
return auth()->user();
}
}
if (!function_exists("team")) {
/**
* @return App\Team
*/
function team() {
return user()->team();
}
}
They’re not crazy or complex. They’re not even a lot of code to type. But I recommend you include them from the start, because you’ll be typing (and type-hinting) the alternatives a lot.
他们并不疯狂也不复杂。 他们甚至不需要输入很多代码。 但我建议您从一开始就将它们包括在内,因为您会经常键入(并提示)替代方法。
9.使用Ngrok来测试Web挂钩 (9. Use Ngrok for Testing Web-Hooks)
It’s rather common to build a product around one or more third-party services. Think about it — you’re already depending on Stripe and/or Braintree. What about when you want to post to Twitter, or send an SMS?
围绕一个或多个第三方服务构建产品是相当普遍的。 考虑一下-您已经依赖Stripe和/或Braintree。 当您想发布到Twitter或发送短信时该怎么办?
When that happens, you’ll often need to provide a web-hook URL. These are routes in your application that respond to (or gather data from) requests from the third-party service. It’s usually a delivery report from a transaction mail service, or confirmation data from that shipping provider.
发生这种情况时,您通常需要提供一个Web挂钩URL。 这些是您的应用程序中的路由,用于响应第三方服务的请求(或从中收集数据)。 通常是来自交易邮件服务的送达报告,或来自该运送提供商的确认数据。
You may be tempted to upload your application to a public server, so these third-party services can reach the web-hook URLs. You could do that (though it’s going to slow your development cycles dramatically) or you could use something like Ngrok to give your local development server an obscure public URL.
您可能会很想将应用程序上载到公共服务器,因此这些第三方服务可以访问Web挂钩URL。 您可以这样做(尽管这会大大降低开发周期),也可以使用Ngrok之类的东西为本地开发服务器提供晦涩的公共URL。
It’s easier than you think. Install Ngrok with Homebrew:
它比您想象的要容易。 使用Homebrew安装Ngrok:
brew install ngrok
…Then serve your Laravel application (presumably with the PHP development server):
…然后为您的Laravel应用程序提供服务(大概与PHP开发服务器一起使用):
php artisan serve
…And in another tab, run Ngrok:
…然后在另一个选项卡中,运行Ngrok:
ngrok http 8000
You’ll see a public url (like http://7d54aeb8.ngrok.io -> localhost:8000
). When you try that URL in your browser, you’ll be able to view your application!
您会看到一个公共网址(例如http://7d54aeb8.ngrok.io -> localhost:8000
)。 在浏览器中尝试该URL时,您将能够查看您的应用程序!
More info about Ngrok available here.
有关Ngrok的更多信息,请点击此处 。
结论 (Conclusion)
If you’re on the fence about trying Spark, I can recommend it. It’s given my product a head-start it wouldn’t have had otherwise. Hopefully these tips will save you even more time. Have you discovered any tips for Spark development? Let your fellow developers know in the comments!
如果您对尝试使用Spark持谨慎态度,那么我建议您这样做。 它为我的产品提供了其他产品无法比拟的领先优势。 希望这些技巧可以为您节省更多时间。 您是否发现了Spark开发的任何技巧? 在评论中让您的其他开发人员知道!
火花思维