Планирование и обработка платежей просты, но не думайте, что повторяющиеся платежи тривиальны. Все может сложиться очень быстро. Вам необходимо решить, как обрабатывать сбои (сколько неудачных попыток оплаты кто-либо получает?), Детали счетов должны обновляться, а планы обновления и понижения могут создавать всевозможные проблемы. Тогда есть, пожалуй, самая значительная проблема с регулярными платежами — вам нужно хранить данные платежа ваших посетителей в файле. Это вводит вопросы безопасности, соответствия и правовые вопросы.
К счастью, Recurly — это сервис, который решает большинство вопросов, связанных с приемом платежей, а также с тех пор обрабатывает повторяющиеся платежи. Используя его библиотеки JavaScript, вы можете создавать безопасные формы для отправки и обновления платежной информации с помощью Recurly, включая все важные данные кредитной карты, которые предоставляют защищенную информацию независимо от вашего приложения.
После того, как вы настроите сумму и частоту платежей, служба позаботится о планировании и принятии платежей через регулярные промежутки времени, пока клиент не решит отменить. Recurly также обрабатывает изменения плана, рассчитывая и делая дополнительные расходы или возмещения.
В этой серии из двух частей я покажу вам шаг за шагом, как создать платный веб-сайт членства на основе подписки с использованием Laravel, платформы на основе PHP5 и службы обработки платежей Recurly. Сначала мы начнем с создания простого сайта с базовой регистрацией, аутентификацией, а также ролями и разрешениями пользователя. Затем мы добавим обработку платежей и включим ее в процесс регистрации, что позволит людям приобретать разные уровни членства.
Настройка приложения
Начните с создания новой папки проекта и выполните следующую команду:
композитор создание-проект laravel / laravel recurly --prefer-dist
Это создает новый проект Laravel с использованием Composer, который загружает фреймворк и его зависимости.
Нам также понадобятся некоторые дополнительные библиотеки для дальнейшего использования, поэтому добавьте следующее в раздел require файла composer.json
и запустите composer.phar update
.
"machuga/authority": "dev-develop", "machuga/authority-l4" : "dev-master", "recurly/recurly-client": "2.1.*@dev"
Это загружает библиотеку Authority, которую мы будем использовать для пользовательских ролей и разрешений, и клиентскую библиотеку Recurly.
Затем настройте соединение с базой данных, указав соответствующее имя схемы, имя пользователя, пароль и имя хоста / адрес в app/config/database.php
. Laravel работает «из коробки» с рядом баз данных, таких как MySQL, Postgres, SQLite и SQL Server.
Нам также нужна таблица пользователей. Вместо того, чтобы настраивать это вручную, Laravel предоставляет миграции, средства для создания и изменения таблиц базы данных программным способом. Запустите следующую команду:
php artisan migrate: создайте create_users_table
Это создает файл миграции в папке app/database/migrations
. Файл создан с базовым контуром, но давайте уточним его с помощью нашего определения таблицы:
public function up() { Schema::create('users', function($table) { $table->increments('id'); $table->string('email')->unique(); $table->string('name'); $table->string('password'); $table->timestamps(); }); } public function down() { Schema::drop('users'); }
Вернитесь в командную строку и запустите:
php ремесленник мигрировать
Загляните в базу данных, и вы обнаружите, что Laravel создал таблицу пользователей для вас.
Настройка полномочий для ролей и разрешений
Чтобы определить тип учетной записи, которую пользователь имеет, и привилегии, которые он ему предоставляет, мы назначим пользователям роль. Мы уже скачали Authority через Composer, чтобы помочь с этим; нам просто нужно выполнить еще несколько шагов, чтобы полностью его настроить.
В app/config/app.php
добавьте следующую строку в провайдеры:
'Authority\AuthorityL4\AuthorityL4ServiceProvider',
Добавьте следующее к псевдонимам:
'Authority' => 'Authority\AuthorityL4\Facades\Authority',
И опубликуйте файл конфигурации Authority:
Конфигурация PHP Artisan: опубликовать Machuga / Authority-L4
Мы вернемся к файлу конфигурации позже. Сейчас нам нужно создать несколько дополнительных таблиц базы данных. К счастью, пакет содержит свои собственные миграции для этого. Запустите их с помощью следующей команды:
php artisan migrate --package = "Machuga / Authority-L4"
Вы обнаружите, что у вас есть три дополнительные таблицы: permissions
, roles
и role_user
.
Нам также необходимо создать модели для представления ролей и разрешений. Мы пока оставим их простыми. В app/models/Role.php
:
<?php class Role extends Eloquent { }
И в app / models / Permission.php:
<?php class Permission extends Eloquent { }
Теперь нам нужно изменить класс модели User
который уже был создан, чтобы связать пользователя с ролями и разрешениями. Добавьте следующие строки в app/models/User.php
:
public function roles() { return $this->belongsToMany('Role'); } public function permissions() { return $this->hasMany('Permission'); } public function hasRole($key) { foreach($this->roles as $role){ if ($role->name === $key) { return true; } } return false; }
Теперь давайте предварительно заполним базу данных некоторыми данными. Откройте app/database/seeds/DatabaseSeeder.php
и вставьте следующее:
<?php class DatabaseSeeder extends Seeder { public function run() { Eloquent::unguard(); $this->call('UserTableSeeder'); $this->command->info('User table seeded!'); $this->call('RoleTableSeeder'); $this->command->info('Role table seeded!'); } } class UserTableSeeder extends Seeder { public function run() { DB::table('users')->delete(); User::create(array( 'email' => '[email protected]', 'name' => 'Joe Bloggs', 'password' => Hash::make('password') )); } } class RoleTableSeeder extends Seeder { public function run() { DB::table('roles')->delete(); Role::create(array('name' => 'admin')); Role::create(array('name' => 'pending')); Role::create(array('name' => 'member')); Role::create(array('name' => 'bronze')); Role::create(array('name' => 'silver')); Role::create(array('name' => 'gold')); } }
Затем запустите базу данных, запустив:
php artisan db: seed
Создание макета
Теперь мы создадим общий макет страницы. Загрузите Twitter Bootstrap и поместите исходные файлы в public
папку — переместите файлы js
в public/js/libs
.
Создайте файл app/views/layouts/default.blade.php
со следующим содержимым:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title>Subscription Site Tutorial</title> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="description" content=""> <meta name="author" content=""> <!-- Le styles --> <link href="/css/bootstrap.css" rel="stylesheet"> <link href="/css/style.css" rel="stylesheet"> </head> <body> <div class="navbar navbar-inverse navbar-fixed-top"> <div class="navbar-inner"> <div class="container"> <button type="button" class="btn btn-navbar" data-toggle="collapse" data-target=".nav-collapse"> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <a class="brand" href="#">Subscription Site Tutorial</a> <div class="nav-collapse collapse"> <ul class="nav"> <li class="active"><a href="#">Home</a></li> <li><a href="#about">About</a></li> <li><a href="#contact">Contact</a></li> </ul> </div><!--/.nav-collapse --> </div> </div> </div> <div class="container"> @if(Session::has('success')) <div class="alert alert-success"> <button type="button" class="close" data-dismiss="alert">×</button> {{ Session::get('success') }} </div> @endif @if(Session::has('error')) <div class="alert alert-error"> <button type="button" class="close" data-dismiss="alert">×</button> {{ Session::get('error') }} </div> @endif @yield('content') </div> <!-- /container --> <!-- Le javascript ================================================== --> <!-- Placed at the end of the document so the pages load faster --> <script src="http://code.jquery.com/jquery-1.10.2.min.js"></script> <script src="/js/libs/bootstrap.min.js"></script> </body> </html>
Это довольно простой материал — содержимое нашей страницы выводится в строке с надписью @yield('content')
.
Далее создайте файл public/css/style.css
:
body { padding-top: 50px; } p.logged-in { color: white; margin-top: 0.5em; }
И, наконец, давайте создадим базовую домашнюю страницу для приложения. Создайте файл app/views/home/index.blade.php
:
@extends('layouts.default') @section('content') <h1>Subscription Site Tutorial</h1> @stop
Объявление @extends
говорит Laravel использовать макет по умолчанию, который мы только что создали с содержимым, которое мы @yield
в область содержимого с помощью команды @yield
обернутой в объявление @section
.
Не забудьте соответственно изменить маршрут по умолчанию в app/routes.php
:
Route::get('/', function() { return View::make('home/index'); });
Создание механизма входа
У нас есть наши пользователи — и учетная запись, с которой можно начать — так что теперь нам нужна возможность войти в систему. В app/routes.php
добавьте маршрут на страницу входа:
Route::get('/auth/login', function() { return View::make('auth/login'); });
Теперь создайте представление app/views/auth/login.blade.php
. Расширение .blade.php
указывает, что мы собираемся использовать библиотеку шаблонов Blade, которая поставляется с Laravel, которая чище, чем прямой PHP. За кулисами эти файлы шаблонов компилируются в PHP по мере необходимости.
@extends('layouts.default') @section('content') <h1>Please Log in</h1> {{ Form::open(array('url' => 'auth/login')) }} {{ Form::label('email', 'E-Mail Address') }} {{ Form::text('email') }} {{ Form::label('password', 'Password') }} {{ Form::password('password') }} <div class="form-actions"> {{ Form::submit('Login', array('class' => 'btn btn-primary')) }} </div> {{ Form::close() }} <p>Not a member? <a href="/user/register">Register here</a>.</p> @stop
Если вы в браузере перейдете к / auth / login, вы должны увидеть простую форму входа.
Чтобы обработать логин, нам нужно построить POST-маршрут. Аутентификация в Laravel очень проста; мы просто делаем это:
Route::post('/auth/login', function() { $email = Input::get('email'); $password = Input::get('password'); if (Auth::attempt(array('email' => $email, 'password' => $password))) { return Redirect::to('/')->with('success', 'You have been logged in'); } else { return Redirect::to('auth/login')->with('error', 'Login Failed'); } return View::make('auth/login'); });
Вся магия происходит в Auth::attempt()
; если вход выполнен успешно, создается сеанс, и заполненный экземпляр объекта User
доступен через статический метод Auth::user()
.
Метод выхода из системы одинаково прост:
Route::get('/auth/logout', function() { Auth::logout(); return Redirect::to('/')->with('success', 'You have successfully logged out'); });
изRoute::get('/auth/logout', function() { Auth::logout(); return Redirect::to('/')->with('success', 'You have successfully logged out'); });
Базовая регистрация
Наша последняя задача в этой части — настроить базовый процесс регистрации. Создайте маршрут регистрации в app/routes.php
:
Route::get('/user/register', function() { return View::make('user/register/index'); });
Теперь создайте представление app/views/user/register/index.blade.php
:
@extends('layouts.default') @section('content') {{ Form::open(array('url' => 'user/register')) }} {{ Form::label('email', 'E-Mail Address') }} {{ Form::text('email') }} {{ $errors->first('email') }} {{ Form::label('name', 'Your name') }} {{ Form::text('name') }} {{ $errors->first('name') }} {{ Form::label('password', 'Password') }} {{ Form::password('password') }} {{ $errors->first('password') }} {{ Form::label('password_confirmation', 'Repeat') }} {{ Form::password('password_confirmation') }} <div class="form-actions"> {{ Form::submit('Register', array('class' => 'btn btn-primary')) }} </div> {{ Form::close() }} @stop
Здесь следует отметить пару вещей:
- Объект
$errors
автоматически передается представлению, независимо от того, есть ли какие-либо ошибки в представлении. Если с полем все в порядке, оно просто ничего не напечатает. -
_confirmation
к имени поля,_confirmation
проверить два поля вместе; т.е. подтвердите, что пользователь повторно ввел выбранный пароль правильно.
Теперь давайте реализуем действие POST:
Route::post('/user/register', function() { $validator = Validator::make( Input::all(), array( 'name' => array('required', 'min:5'), 'email' => array('required', 'email', 'unique:users'), 'password' => array('required', 'confirmed') ) ); if ($validator->passes()) { $user = new User(); $user->name = Input::get('name'); $user->email = Input::get('email'); $user->password = Hash::make(Input::get('password')); $user->save(); $role_pending = Role::where('name', '=', 'pending')->first(); $user->roles()->attach($role_pending); Auth::login($user); return Redirect::to('/')->with( 'success', 'Welcome to the site, . Auth::user()->name . '!' ); } else { return Redirect::to('user/register')->with( 'error', 'Please correct the following errors:' )->withErrors($validator); } });
Это все довольно простые вещи — мы создаем валидатор, передавая ему POST-переменные с помощью Input::all()
и набора правил валидации. Если проверка пройдена, мы создаем нового пользователя, назначаем его ожидающей роли, регистрируем его, а затем перенаправляем на первую страницу.
Если проверка не пройдена, мы перенаправляем обратно в форму, создаем флэш-сообщение об ошибке и передаем сообщения об ошибках из валидатора — они затем будут доступны в представлении в переменной $errors
.
Вывод
В этой части мы шаг за шагом прошли через создание голого сайта подписки. Он имеет возможность зарегистрировать базовую учетную запись, войти и выйти. В следующей части мы интегрируем Recurly для платных планов подписки.