В этом уроке мы увидим, как легко создать базовый платный веб-сайт для членов с помощью пакета Laravel Cashier . Вы можете увидеть демо приложения здесь и скачать исходный код здесь .
Настройка рабочей среды
Нам нужно создать проект Boilreplate, чтобы начать, и мы можем сделать это двумя различными способами:
- мы можем клонировать репозиторий Github в папку нашего проекта.
- Предполагая, что у вас установлен
composer, (см. Руководство по установке для получения более подробной информации).
мы запускаемcomposer create-project laravel/laravel laravel_membership --prefer-dist, это создаст шаблонный проектlaravel_membershipв нашей папкеlaravel_membership.
Теперь нам нужно запросить пакет Laravel Cashier "laravel/cashier": "~1.0" для проекта, добавив "laravel/cashier": "~1.0" в наш composer.json в разделе require и запустите composer update для обновления наших зависимостей.
После этого нам нужно сообщить нашему приложению о загрузке класса провайдера услуг Cashier . Мы можем сделать это, добавив "Laravel\Cashier\CashierServiceProvider" в массив providers в файле config/app.php .
Примечание : вы должны запустить composer dump-autoload classMap package для обновления classMap package .
Создание базы данных с использованием миграций
Если вы новичок в Laravel Migrations , обязательно ознакомьтесь с документацией .
Мы собираемся использовать две таблицы:
таблица posts :
— INT id
— STRING title
— LONG_TEXT content
— BOOL is_premium
таблица users :
— INT id
— VARCHAR(60) email
— VARCHAR(60) password
Инструмент командной строки Laravel artisan позволяет легко создавать и управлять классами миграции.
php artisan migrate : make create_posts_table -- create = "posts" php artisan migrate : make create_users_table -- create = "users"
а затем мы заполняем аргумент функции обратного вызова Schema::create необходимым кодом, который выглядит следующим образом
Schema :: create ( 'posts' , function ( Blueprint $table )
{ $table -> increments ( 'id' ); $table -> string ( 'title' ); $table -> longText ( 'content' ); $table -> boolean ( "is_premium" ); $table -> timestamps ();
});
Schema :: create ( 'users' , function ( Blueprint $table )
{ $table -> increments ( 'id' ); $table -> string ( 'email' , 100 )-> unique (); $table -> string ( 'password' , 60 ); $table -> timestamps ();
});
Чтобы Laravel Cashier знал о нашей оплачиваемой таблице, нам нужно создать для этого специальную миграцию. Laravel Cashier имеет встроенную команду.
php artisan cashier : table users
Теперь мы готовы перенести нашу базу данных
php artisan migrate
если вы откроете таблицу users то увидите, что при переносе пакета будет добавлено несколько полей.
— stripe_active если у вас есть активная подписка.
— stripe_id пользователя stripe_id на сервере Stripe.
stripe_plan план подписки Stripe.
— последние четыре цифры кредитной карты last_four .
— trial_ends_at дата окончания сохраняется, если вы указываете пробный период.
— subscription_ends_at дата окончания подписки.
Теперь мы заполним базу данных некоторыми фиктивными данными, чтобы начать; проверьте окончательный результат на GitHub .
Процесс биллинга
Работа с платежами может быть проблемой в шее, и Stripe может помочь вам в этом, они используют tokens вместо номеров карт и т. Д., И таким образом вы можете быть уверены, что ваши клиенты будут в безопасности, оплачивая ваши услуги.
ПРИМЕЧАНИЕ. Проверьте, поддерживается ли Stripe в вашей стране, но вы все равно можете использовать его для тестирования, если нет.
Для начала нам нужно сначала получить аккаунт. Stripe не имеет ежемесячной платы за подписку, вы платите только тогда, когда вам платят.
Теперь, после получения учетной записи, вам нужно создать Планы для вашего приложения (Ежемесячно, Ежегодно, Серебро, Золото …).
Каждое поле не требует пояснений, поэтому давайте создадим Gold членство, которое будет стоить 40 долларов, и базовое членство за 10 долларов. Они будут выставляться счета каждый месяц.
Мы уже добавили необходимые столбцы в нашу таблицу users , теперь нам нужно сообщить Laravel Cashier , что мы будем использовать класс User качестве нашего класса биллинга.
use Laravel \Cashier\BillableInterface ;
use Laravel \Cashier\BillableTrait ;
class User extends Eloquent implements BillableInterface {
use BillableTrait ;
protected $dates = [ 'trial_ends_at' , 'subscription_ends_at' ];
Примечание: мы используем BillableTrait и для его использования требуется PHP 5.4 или выше.
Теперь нам нужно установить наш ключ доступа Stripe API, который вы можете получить из Your account > Account settings > API Keys и скопировать свой Test Secret Key .
Используя BillableTrait мы получаем доступ к User::setStripeKey(key) который можно вызывать в любом месте нашего кода, но предпочтительным способом является создание файла services.php в каталоге config и возврат массива, подобного следующему:
return [
'stripe' => [
'secret' => 'Your key'
]
];
Когда getStripeKey пытается загрузить ваш ключ, он будет искать свойство с именем stripeKey . Если он не найден, он автоматически загрузит ваш services файл.
Создание наших страниц
Для простоты мы создадим всего несколько страниц:
— Регистрация: где пользователь может зарегистрироваться с помощью плана членства (Basic, Gold).
— Логин: страница входа членов.
— Обновление: обновление с базового до золотого членства.
— Опубликовать: отображать одну страницу сообщения.
Для ускорения процесса мы будем использовать bootsnipp . Вы можете получить окончательный код из репозитория GitHub.
Страница авторизации:
Страница входа имеет основное поле электронной почты и пароль, а страница LoginController выглядит следующим образом:
public function index (){
return View :: make ( 'login' );
}
public function store (){
if ( Auth :: attempt ( Input :: only ( [ 'email' , 'password' ] ), true )){
return Redirect :: to ( '/' );
}
else {
return Redirect :: back ()-> withInput ()-> with ( 'message' , 'Email or password incorrect' );
}
}
public function destroy (){
Auth :: logout ();
return Redirect :: route ( "login" );
}
Страница регистрации:
На странице регистрации есть поле Subscription plan используемое для назначения пользователю плана.
У нас также есть номер Credit card number , Expiration date , CVC .
Как мы уже говорили ранее, нам никогда не придется иметь дело с каким-либо процессом оплаты или проверки, мы передаем эти значения на сервер Stripe, чтобы позаботиться о процессе зарядки и проверки.
Возвращаемое значение является токеном в случае успеха, в противном случае мы получаем сообщение об ошибке, которое мы можем показать пользователю.
Давайте посмотрим, как выглядит интерфейсный код:
<script type = "text/javascript" src = "https://js.stripe.com/v2/" ></script>
<script>
Stripe . setPublishableKey ( 'Your public key' ); jQuery ( function ( $ ) { $ ( '#subscription-form' ). submit ( function ( event ) {
var $form = $ ( this ); $form . find ( 'button' ). prop ( 'disabled' , true );
Stripe . card . createToken ( $form , stripeResponseHandler );
return false ;
});
});
var stripeResponseHandler = function ( status , response ) {
var $form = $ ( '#subscription-form' );
if ( response . error ) { $form . find ( '.payment-errors' ). text ( response . error . message ); $form . find ( 'button' ). prop ( 'disabled' , false );
} else {
var token = response . id ; $form . append ( $ ( '<input type="hidden" name="stripeToken" />' ). val ( token )); $form . get ( 0 ). submit ();
}
};
</script>
Сначала мы включаем файл JavaScript API, затем устанавливаем наш открытый ключ, который мы взяли из настроек панели Stripe.
Затем мы присоединяем функцию обратного вызова к нашей форме отправки (убедитесь, что ваш идентификатор формы совпадает с идентификатором, используемым в обработчике событий), чтобы предотвратить двойную отправку, мы отключаем нашу кнопку отправки.
Stripe.card.createToken принимает два аргумента, первый — это объект JSON, имеющий некоторые обязательные и дополнительные значения.
Обязательные значения:
-
number:numberкарты в виде строки без разделителей. -
exp_month: двухзначное число, обозначающее месяц истечения срока действия карты. -
exp_year: двух или четырехзначное число, обозначающее год истечения срока действия карты.
Необязательные значения:
-
cvc: код безопасности карты в виде строки, номерcvcне обязателен, но рекомендуется для предотвращения мошенничества. -
name: имя владельца карты. -
address_line1: адресная строка для выставления счетов 1. -
address_line2: адресная строка для выставления счетов 2. -
address_city: город для выставления счетов. -
address_state: состояние адреса выставления счета. -
address_zip: почтовый индекс в виде строки. -
address_country: страна для выставления счетов.
Вы можете заметить, что мы передаем объект формы вместо объекта JSON, вы можете выбрать захват значений вручную или использовать атрибутdata-stripehtml5 на своих входах, и Stripe будет использовать некоторые вспомогательные методы для автоматического получения этих значений для вас. , Пример:
<input data-stripe = "number" type = "text" >
Второй аргумент, передаваемый методу Stripe.card.createToken является функцией обратного вызова для обработки ответа.
В случае сбоя stripeResponseHandler попытается найти элемент с классом payment_errors чтобы отобразить некоторые описательные ошибки для пользователя.
В случае успеха скрытый ввод stripeToken будет добавлен в форму и будет доступен после отправки.
Дополнительные опции
-
Trial periods: как мы указывали ранее, при создании нового плана у вас есть выбор указать пробный период для пользователей, чтобы протестировать ваш продукт, и с них не будет взиматься плата до истечения указанного периода. -
Coupons: вы создаете купоны через меню панели инструментов, где вы можете указать фиксированную сумму или в процентах, с некоторыми другими полезными опциями.
Теперь давайте перейдем к нашему SignupController чтобы посмотреть, как мы будем это SignupController .
public function store (){ $user = new User ; $user -> email = Input :: get ( 'email' ); $user -> username = Input :: get ( 'username' ); $user -> password = Hash :: make ( Input :: get ( 'password' ) ); $user -> save (); $user -> subscription ( Input :: get ( 'subscription' ))-> create ( Input :: get ( 'stripeToken' ) );
return 'you are now registred' ;
}
Мы пропустим процесс проверки, чтобы все было просто.
После создания нового User и его сохранения у нас теперь есть возможность подписать пользователя на новый тарифный план. Метод subscription принимает в качестве аргумента уже зарегистрированный план, который может быть PlanInterface или String и возвращает StripeGateway .
Метод create принимает токен в качестве параметра; мы передаем новое скрытое входное значение с именем stripeToken .
Обновить страницу:
Страница обновления будет UpgradeController в UpgradeController который выглядит следующим образом:
public function store (){
if ( ! Auth :: check () )
return Redirect :: route ( "login" );
Auth :: user ()-> subscription ( 'gold' )-> swap ();
return 'You are now a GOLD member' ;
}
Сначала мы проверяем, вошел ли пользователь в систему, затем создаем новую subscription с новым планом и вызываем метод swap , очевидно, в реальном проекте у вас будут некоторые корректировки платы и опция понижения, но она должна работать так же ,
Страница поста:
PostController проверяет, является ли is_premium , и если так, мы проверяем, является ли пользователь золотым участником, который может видеть пост, иначе мы возвращаем простое сообщение об ошибке.
public function show ( $id ){ $post = Post :: find ( $id );
if ( $post -> is_premium && Auth :: user ()-> stripe_plan != 'gold' )
return View :: make ( 'error' , [ 'message' => 'Only GOLD members can read this post, <a href="/upgrade">upgrade</a> your membership to get access' ] );
return View :: make ( 'post' , [ 'post' => $post ] );
} //show
Конечно, в нашем файле routes.php нам нужно добавить фильтр routes.php чтобы предотвратить доступ к странице неаутентифицированным пользователям.
Наш файл маршрутов будет выглядеть так:
Route :: get ( '/' , function ()
{ $posts = Post :: all ();
return View :: make ( 'index' , [ 'posts' => $posts ]);
})-> before ( 'auth' );
Route :: get ( '/post/{id}' , [ 'as' => 'post' , 'uses' => 'PostsController@show' ])-> before ( 'auth' );
Route :: resource ( 'login' , 'LoginController' , [ 'only' => [ 'index' , 'store' , 'destroy' ] ]);
Route :: resource ( 'signup' , 'SignupController' , [ 'only' => [ 'index' , 'store' ] ]);
Route :: resource ( 'upgrade' , 'UpgradeController' , [ 'only' => [ 'index' , 'store' ] ]);
Другие полезные методы
-
withCoupon: мы говорили ранее, что у нас есть возможность создавать купоны на скидку, в нашем примере мы можем сделать это так:
$user -> subscription ( Input :: get ( 'subscription' ))-> withCoupon ( 'coupon code' )-> create ( Input :: get ( 'stripeToken' ) );
-
cancel: вы можете легко отменить подписку, используя этот метод, но вы должны проверить, является ли пользовательonGracePeriodчтобы убедиться, что вы не заблокируете его немедленно:
User :: find ( 1 )-> onGracePeriod ();
-
onPlan: посмотреть, есть ли у пользователя определенный план. -
onTrial: посмотреть, находится ли пользователь еще на испытательном сроке. -
canceled: если пользователь отменил свою подписку. -
getLastFourCardDigits: получить последние четыре цифры пользовательской карты. -
getSubscriptionEndDate: получить дату окончания подписки. -
getTrialEndDate: получить дату окончания пробной версии. -
invoices: получить список пользовательских счетов. -
findInvoice: найти счет по идентификатору. -
downloadInvoice: создать загружаемый счет по идентификатору.
Вывод
В этом руководстве мы рассмотрели, как Laravel Cashier может упростить процесс выставления счетов и упростить управление вашими клиентами.
Мы, конечно, не все здесь описали, но для вас стоит начать копаться в исходном коде, чтобы узнать, что еще можно сделать. Если вы хотите посмотреть демоверсию этого приложения на Nitrous, смотрите здесь .





