Это руководство является частью серии « Создай свой стартап с помощью PHP» на Envato Tuts +. В этой серии я проведу вас через запуск стартапа от концепции до реальности, используя мое приложение Meeting Planner в качестве примера из реальной жизни. На каждом этапе я буду публиковать код Планировщика собраний в качестве примеров с открытым исходным кодом, из которых вы можете извлечь уроки. Я также буду решать вопросы, связанные с бизнесом по мере их возникновения.
Недавно я спросил, вдохновила ли наша серия стартапов какие-либо ваши собственные предпринимательские идеи и заставила ли вас писать код. Если это так, пожалуйста, поделитесь немного с нами в комментариях.
Давайте встретимся, посетите страницу моего расписания со мной
В течение долгого времени с тех пор, как я начал этот проект, я хотел, чтобы у Meeting Planner и Simple Planner была общедоступная страница, которой вы могли бы поделиться с людьми, чтобы запланировать встречу с вами. Другими словами: «Конечно, давайте встретимся, просто зайдите на страницу моего расписания со мной в Meeting Planner, я — Берни Сандерс (нет места)».
В сегодняшнем уроке я покажу вам, что я сделал это, используя маршрутизацию Yii и некоторые связанные с этим проблемы.
Если вы еще не пробовали запланировать встречу , вы можете увидеть, как это делается, в этом видео:
Страница «Расписание со мной» будет похожа на страницу PayPal Pay Me:
Я принимаю участие в комментариях ниже, так что скажите мне, что вы думаете! Вы также можете связаться со мной в Твиттере @lookahead_io . Мне особенно интересно, если вы хотите новые функции или предложить темы для будущих уроков.
Напоминаем, что весь код для Meeting Planner написан на Yii2 Framework для PHP. Если вы хотите узнать больше о Yii2, ознакомьтесь с нашей параллельной серией Программирование с Yii2 .
Давайте начнем.
Планирование расписания со мной
Примечание: насколько я знаю, Берни на самом деле не пользователь Планировщика собраний.
У каждого пользователя Планировщика собраний есть уникальное имя, например, berniesanders, и я решил использовать его для расписания с URL-адресом. У этой функции было несколько проблем:
- Дизайн страницы
- Работа с Yii Routing для сопоставления корневого пути каждому человеку
- Управление регистрацией, входом в систему и возвращением в расписание
Дизайн страницы
Вдохновленный страницей PayPal Pay Me (см. Выше) и другими подобными, я хотел, чтобы сначала все было просто. Я использовал адаптивную сетку со смещением и центрированием:
1
2
3
4
|
<div class=»col-lg-8 col-lg-offset-2
col-xs-10 col-xs-offset-1
col-md-8 col-md-offset-2″>
<div class=»centered schedule-me»>
|
Вот /frontend/views/meeting/scheduleme.php представление для страницы:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
<div class=»scheduleme-top»>
<div class=»row»>
<div class=»col-lg-8 col-lg-offset-2 col-xs-10 col-xs-offset-1 col-md-8 col-md-offset-2″>
<div class=»centered schedule-me»>
<?php
if ($userprofile->avatar<>») {
echo ‘<img src=»‘.Yii::getAlias(‘@web’).’/uploads/avatar/sqr_’.$userprofile->avatar.’» class=»profile-image»/>’;
} else {
echo \cebe\gravatar\Gravatar::widget([
’email’ => $user->email,
‘options’ => [
‘class’=>’profile-image’,
‘alt’ => $user->username,
],
‘size’ => 128,
]);
}
?>
<h1><?= $displayName ?></h1>
<p class=»lead»>
<?php if (Yii::$app->user->isGuest) { ?>
<?= Html::a(Yii::t(‘frontend’,’Schedule a meeting with me’),[‘site/signup’])?>
<?php } else { ?>
<?= Html::a(Yii::t(‘frontend’,’Schedule a meeting with me’),[‘meeting/create’,’with’=>$user->username])?>
<?php } ?>
<p>
</div>
</div>
</div>
</div>
|
Код отображает изображение профиля, загруженное пользователем в настройках пользователя или использующее общий Gravatar.
Конечно, я использовал /frontend/web/css/site.css для настройки полей, границы и фона:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
.scheduleme-top {
margin-top:8%;
}
.schedule-me {
background-color:#f3f3f3;
min-width:500px;
padding:100px 25px 65px 25px;
border:1px solid #e0e0e0;
}
// responsive adjustments
@media only screen
and (min-device-width: 320px)
and (max-device-width: 667px)
and (-webkit-min-device-pixel-ratio: 2) {
…
.schedule-me {
min-width:75%;
padding:60px 10px 40px 10px;
}
|
Управление изменениями маршрутизации Yii
Маршрутизация того, как Yii обрабатывает входящие запросы браузера, обрабатывается в /frontend/config/main.php в компонентах. Если вы не будете осторожны с настройкой этого, вы можете уничтожить все ваше приложение, так как входящие запросы не будут отображаться на страницах с ошибками.
Вот более ранняя маршрутизация до графика со мной:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
|
<?php
$config = parse_ini_file(‘/var/secure/mp.ini’, true);
$params = array_merge(
require(__DIR__ . ‘/../../common/config/params.php’),
require(__DIR__ . ‘/../../common/config/params-local.php’),
require(__DIR__ . ‘/params.php’),
require(__DIR__ . ‘/params-local.php’)
);
return [
‘components’ => [
…
‘urlManager’ => [
‘class’ => ‘yii\web\UrlManager’,
‘enablePrettyUrl’ => true,
‘showScriptName’ => false,
//’enableStrictParsing’ => false,
‘rules’ => [
‘place’ => ‘place’,
‘place/yours’ => ‘place/yours’,
‘place/create’ => ‘place/create’,
‘place/create_geo’ => ‘place/create_geo’,
‘place/create_place_google’ => ‘place/create_place_google’,
‘place/view/<id:\d+>’ => ‘place/view’,
‘place/update/<id:\d+>’ => ‘place/update’,
‘place/<slug>’ => ‘place/slug’,
‘<controller:\w+>/<id:\d+>’ => ‘<controller>/view’,
‘<controller:\w+>/<action:\w+>/<id:\d+>’ => ‘<controller>/<action>’,
‘daemon/<action>’ => ‘daemon/<action>’, // incl eight char action
‘site/<action>’ => ‘site/<action>’, // incl eight char action
‘features’ => ‘site/features’,
‘about’ => ‘site/about’,
‘wp-login|wp-admin’ => ‘site/neverland’,
‘<username>/<identity:[A-Za-z0-9_-]{8}>’ => ‘meeting/identity’,
// note — currently actions with 8 letters and no params will fail
‘<controller:\w+>/<action:\w+>’ => ‘<controller>/<action>’,
],
|
Ранее я писал о маршрутах в статье Как программировать с помощью Yii2: медленное поведение , часть нашей серии программ по Yii , и вы можете прочитать дополнительную информацию в документации по Yii .
В статье «Создание стартапа: встречи с несколькими участниками» я написал два эпизода о динамических путях по имени пользователя для уникальных URL-адресов собраний, как показано ниже:
'<username>/<identity:[A-Za-z0-9_-]{8}>' => 'meeting/identity',
Это сломало множество маршрутов из двух элементов, таких как meeting / [meeting_id], пока я не поднял более динамическое отображение над ним, чтобы иметь приоритет:
1
2
|
‘<controller:\w+>/<id:\d+>’ => ‘<controller>/view’,
‘<controller:\w+>/<action:\w+>/<id:\d+>’ => ‘<controller>/<action>’,
|
И любые пути к второму элементу с символами должны быть определены статически, потому что наши строки идентификаторов для собраний состоят из восьми символов, например, features
.
Такие маршруты, как features
являются фиксированными, что относится к sites
контроллеров и features
действий, как показано выше. Остальные функции отображаются динамически, как в: '<controller:\w+>/<action:\w+>' => '<controller>/<action>',
,.
Попытка создать маршрут из динамической переменной из одного элемента, такой как / [имя пользователя], например, https://meetingplanner.io/berniesanders , сломал множество маршрутов из одного элемента, таких как https://meetingplanner.io/about и страницу напоминаний. https://meetingplanner.io/reminder .
Поэтому мне пришлось начать статически определять многие из них.
Вот окончательная маршрутизация с новыми статическими маршрутами для путей из одного слова:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
|
‘urlManager’ => [
‘class’ => ‘yii\web\UrlManager’,
‘enablePrettyUrl’ => true,
‘showScriptName’ => false,
//’enableStrictParsing’ => false,
‘rules’ => [
‘place’ => ‘place’,
‘place/yours’ => ‘place/yours’,
‘place/create’ => ‘place/create’,
‘place/create_geo’ => ‘place/create_geo’,
‘place/create_place_google’ => ‘place/create_place_google’,
‘place/view/<id:\d+>’ => ‘place/view’,
‘place/update/<id:\d+>’ => ‘place/update’,
‘place/<slug>’ => ‘place/slug’,
‘<controller:\w+>/<id:\d+>’ => ‘<controller>/view’,
‘<controller:\w+>/<action:\w+>/<id:\d+>’ => ‘<controller>/<action>’,
‘daemon/<action>’ => ‘daemon/<action>’, // incl eight char action
‘site/<action>’ => ‘site/<action>’, // incl eight char action
‘features’ => ‘site/features’,
‘about’ => ‘site/about’,
‘wp-login|wp-admin’ => ‘site/neverland’,
‘<username>/<identity:[A-Za-z0-9_-]{8}>’ => ‘meeting/identity’,
‘meeting’ => ‘meeting’,
‘friend’ => ‘friend’,
‘reminder’ => ‘reminder’,
‘user-contact’ => ‘user-contact’,
‘user-profile’ => ‘user-profile’,
‘user-setting’ => ‘user-setting’,
‘<username>’ => ‘meeting/scheduleme’,
// note — currently actions with 8 letters and no params will fail
‘<controller:\w+>/<action:\w+>’ => ‘<controller>/<action>’,
],
],
|
И вы можете проверить «страницу Берни» и запланировать встречу с ним здесь:
https://simpleplanner.io/berniesanders
Примечание: Meeting Planner и Simple Planner работают взаимозаменяемо, и я использую оба сайта, чтобы предлагать пользователям несколько брендов. Simple Planner — для социальных встреч, а Meeting Planner — для более деловых вещей.
Управление регистрацией и входом со страницы «Расписание со мной»
Большинство людей, которые первоначально посещают страницу со мной, не имеют учетной записи. Таким образом, они будут перенаправлены, когда нажмут « Расписание со мной» на страницу регистрации или входа.
После того, как они войдут в систему, мы хотим вернуть их на страницу создания собрания, на которой предварительно загружен владелец расписания, а страница со мной добавлена в качестве участника. Мы используем setReturnUrl
чтобы сделать это:
1
|
Yii::$app->user->setReturnUrl([‘meeting/create/’,’with’=>$u->username]);
|
Он обновляет сеанс (обычно через cookie), так что после того, как человек регистрируется или входит в систему, он возвращается на целевую страницу.
Вот полный метод /frontend/controllers/MeetingController.php actionScheduleme
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
|
public function actionScheduleme() {
$username = Yii::$app->request->getPathInfo();
$u = User::find()
->where([‘username’=>$username])
->one();
if (is_null($u)) {
return $this->goHome();
} elseif (!Yii::$app->user->isGuest) {
if (Yii::$app->user->getId()==$u->id) {
Yii::$app->getSession()->setFlash(‘info’, Yii::t(‘frontend’,’Welcome to your public scheduling page.’));
}
}
$userprofile = \frontend\models\UserProfile::find()
->where([‘user_id’=>$u->id])
->one();
Yii::$app->user->setReturnUrl([‘meeting/create/’,’with’=>$u->username]);
return $this->render(‘scheduleme’, [
‘user’=>$u,
‘displayName’=> MiscHelpers::getDisplayName($u->id,true),
‘userprofile’ => $userprofile,
]);
}
|
Добавление владельца страницы расписания в качестве участника
Вот метод /frontend/controllers/MeetingController.php actionCreate
:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public function actionCreate($with = »)
{
…
if ($with<>») {
$u = User::find()
->where([‘username’=>$with])
->one();
if (!is_null($u)) {
$with_id =$u->id;
} else {
Yii::$app->getSession()->setFlash(‘error’, Yii::t(‘frontend’,’Sorry, we could not locate anyone by that name. Visit support if you need assistance.’));
$with_id =0;
}
} else {
$with_id =0;
}
// prevent creation of numerous empty meetings
$meeting_id = Meeting::findEmptyMeeting(Yii::$app->user->getId(),$with_id);
if ($meeting_id===false) {
// otherwise, create a new meeting
$model = new Meeting();
$model->owner_id= Yii::$app->user->getId();
$model->sequence_id = 0;
$model->meeting_type = 0;
$model->subject = Meeting::DEFAULT_SUBJECT;
$model->save();
$model->initializeMeetingSetting($model->id,$model->owner_id);
$meeting_id = $model->id;
}
if ($with_id!=0) {
Participant::add($meeting_id,$with_id,Yii::$app->user->getId());
}
$this->redirect([‘view’, ‘id’ => $meeting_id]);
}
|
Он обрабатывает идентификатор пользователя расписания со мной, владельцем страницы, как $with_id
чтобы добавить их в качестве участника. Кроме того, сначала проверяется, что между этими двумя людьми уже нет встречи, чтобы избежать дублирования:
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
|
public static function findEmptyMeeting($user_id,$with_id = 0) {
// if meeting with someone see if it exists already
if ($with_id!=0) {
// check for meeting with one participant with with_id
$meetings = Meeting::find()->where([‘owner_id’=>$user_id,’status’=>Meeting::STATUS_PLANNING])->limit(7)->orderBy([‘id’ => SORT_DESC])->all();
foreach ($meetings as $m) {
if (!is_null($m) && (count($m->participants)==1 && $m->participants[0]->participant_id==$with_id)) {
return $m->id;
}
}
}
// looks for empty meeting in last seven
$meetings = Meeting::find()->where([‘owner_id’=>$user_id,’status’=>Meeting::STATUS_PLANNING])->limit(7)->orderBy([‘id’ => SORT_DESC])->all();
foreach ($meetings as $m) {
if (!is_null($m) and ($m->subject==Meeting::DEFAULT_SUBJECT || $m->subject==») and (count($m->participants)==0 && count($m->meetingPlaces)==0 && count($m->meetingTimes)==0)) {
return $m->id;
}
}
return false;
}
|
Первоначально я добавил эту функцию, чтобы пользователи не могли создавать новые собрания, когда уже было другое пустое новое собрание, которое они создали ранее.
Заглядывая вперед
В будущем на этой странице будут некоторые вещи, которые я уберу, когда буду общаться с реальными пользователями и собирать отзывы. Возможно, я автоматически поделюсь с друзьями самыми частыми днями и временем встреч. И я создам пользовательскую настройку, чтобы отключить вашу страницу планирования на случай, если она вам не нужна.
В заключение
Вся работа, которую я недавно проделал с Bootstrap по созданию лучшего адаптивного интерфейса для Meeting Planner, упростила мне быстрое программирование страницы со мной.
Сложнее всего было убедиться, что новые маршруты Yii работают и ничего не сломали на сайте. Я также пошел и проверил все свои Ajax-звонки, чтобы убедиться, что ни один из них не был затронут.
Я надеюсь, что сегодняшний урок был полезен для вас, чтобы научиться настраивать URL-адреса сайтов для вашей пользовательской базы и основы маршрутизации MVC.
Есть свои мысли? Идеи? Обратная связь? Вы всегда можете связаться со мной через Twitter @lookahead_io напрямую. Следите за будущими уроками здесь в серии « Построение стартапа с помощью PHP» . Некоторые интересные функции уже в пути.
Опять же, если вы еще не опробовали Планировщик собраний или Простой планировщик , запланируйте свою первую встречу .
Ссылки по теме