German (Deutsch) translation by Wei Zhang (you can also view the original English article)



Dies ist der fünfte Teil der Building Your Startup With PHP-Reihe für Tuts +. In dieser Serie führe ich Sie durch den Start eines Konzepts vom Konzept zur Realität, wobei Sie meine Meeting Planner-App als reales Beispiel verwenden. Bei jedem Schritt werden wir den Meeting Planner-Code als Open Source-Beispiele veröffentlichen, von denen Sie lernen können. Wir werden auch unternehmensinterne Probleme beim Start behandeln.
Der gesamte Code für Meeting Planner ist im Yii2 Framework für PHP geschrieben. Wenn Sie mehr über Yii2 erfahren möchten, sehen Sie sich unsere parallele Serie Programming With Yii2 unter Tuts + an.
In diesem Lernprogramm werde ich Sie durch weitere Funktionen des Yii-Frameworks führen, mit denen der vorhandene Code für die Bereichsverwaltung robuster wird. Wir implementieren die einfache Zugriffskontrolle von Yii, um sicherzustellen, dass nur angemeldete Benutzer Orte hinzufügen. Wir werden Active Record-Beziehungen verwenden, sodass nur Orte angezeigt werden, die der Benutzer hinzugefügt hat, in der Ansicht der Bereichsindexseite. Wir werden auch Yiis träge Verhalten verwenden, um URL-freundliche Slugs für die Anzeige dieser Orte zu implementieren. Außerdem werden wir die Place-Funktionen ein wenig bereinigen und verbessern.
Nur zur Erinnerung, ich beteilige mich an den Kommentarthreads unten. Ich bin besonders interessiert, wenn Sie unterschiedliche Ansätze oder zusätzliche Ideen haben oder wenn Sie Themen für zukünftige Tutorials vorschlagen möchten. Ich freue mich auch über Funktionsanfragen für den Meeting Planner.
Zugangskontrolle
Der Code, den wir bisher geschrieben haben, ermöglicht es jedem, Orte zu erstellen, auch wenn er sich nicht angemeldet hat. Wir können die einfachen Zugriffskontrollfunktionen von Yii2 verwenden, um sicherzustellen, dass sich Benutzer registrieren und anmelden, bevor sie Orte hinzufügen und anzeigen.
Yii2 bietet auch eine erweiterte (und komplexe) rollenbasierte Zugriffssteuerung (Role Based Access Control, RBAC), die wir derzeit nicht implementieren werden.
Wenn Benutzer beim Besuch der Ortsseiten nicht angemeldet sind, werden sie von Yii auf die Anmeldeseite umgeleitet.
Die integrierte Zugriffskontrolle von Yii2 unterstützt standardmäßig nur zwei Rollen: guest (nicht angemeldet), dargestellt durch "?", Und authentifiziert, dargestellt durch "@". Wenn Sie interessiert sind, hat The Code Ninja ein schönes Beispiel dafür geschrieben, wie Sie dies für die Unterstützung von Moderatoren und Administratoren (Simpler Role Based Authorization in Yii 2.0) erweitern können, ohne RBAC verwenden zu müssen.
Das Framework macht es recht einfach, diese Steuerelemente zu implementieren. Wir fügen einfach zu PlaceController.php Verhalten hinzu, die die Zugriffsregeln für jede Aktion definieren, z. Indexieren, Erstellen, Anzeigen usw. Hier überprüfen wir das Zugriffsverhalten. Wenn Sie jedoch interessiert sind, können Sie mit den Verb-Filtern von Yi die http-Vorgänge auf der Grundlage Ihrer Controller-Aktion beschränken.
1 |
public function behaviors() |
2 |
{
|
3 |
return [ |
4 |
'verbs' => [ |
5 |
'class' => VerbFilter::className(), |
6 |
'actions' => [ |
7 |
'delete' => ['post'], |
8 |
],
|
9 |
],
|
10 |
'access' => [ |
11 |
'class' => \yii\filters\AccessControl::className(), |
12 |
'only' => ['index','create', 'create_geo','create_place_google','update','view','slug'], |
13 |
'rules' => [ |
14 |
// allow authenticated users
|
15 |
[
|
16 |
'allow' => true, |
17 |
'roles' => ['@'], |
18 |
],
|
19 |
// everything else is denied
|
20 |
],
|
21 |
],
|
22 |
];
|
23 |
}
|
Wenn Sie nach dem Hinzufügen auf das Menü Orte klicken, werden Sie zur Anmeldeseite weitergeleitet:



Yii übernimmt auch die Weiterleitung zur Indexseite, sobald die Anmeldung abgeschlossen ist.
Wenn Benutzer auf die Ortsseiten zugreifen, können wir den aktuellen Benutzer mit diesem Code finden:
Yii::$app->user->getId();
Kurz bevor neue Orte gespeichert werden, können Sie also das Feld created_by
auf den aktuell angemeldeten Benutzer aktualisieren. Und wir können den Zugriffskontrollen vertrauen, um sicherzustellen, dass nur authentifizierte Benutzer auf die Erstellungsmethode zugreifen können:
1 |
public function actionCreate() |
2 |
{
|
3 |
$model = new Place(); |
4 |
if ($model->load(Yii::$app->request->post())) { |
5 |
$form = Yii::$app->request->post(); |
6 |
$model->created_by= Yii::$app->user->getId(); |
7 |
$model->save(); |
Aktive Datensatzbeziehungen
In Meeting Planner möchte ich nachverfolgen, welcher Benutzer zuerst einen Ort erstellt. Diese wird im Feld created_by
gespeichert. Wir möchten auch Orte ermitteln, die Benutzer für ihre Besprechungen vorschlagen und verwenden, die Häufigkeit, mit der sie Orte verwenden, und ihre Favoriten. Wir verwenden dazu die UserPlace-Tabelle.
Da wir nun wissen, welcher Benutzer beim Erstellen eines Bereichs angemeldet ist, möchten wir auch eine relationale Zeile in der UserPlace-Tabelle auffüllen.
Zuerst müssen wir den Code-Generator von Yi, Gii (http://localhost:8888/mp/index.php/gii /model), verwenden, um ein Modell für UserPlace zu erstellen:



Wenn ein Ort erfolgreich hinzugefügt wurde, möchten wir einen Datensatz in der UserPlace-Tabelle für den aktiven Benutzer erstellen. Wir können Yii ActiveRecord mit der afterSave
-Methode erweitern. Im Place-Modell fügen wir hinzu:
1 |
public function afterSave($insert,$changedAttributes) |
2 |
{
|
3 |
parent::afterSave($insert,$changedAttributes); |
4 |
if ($insert) { |
5 |
$up = new UserPlace; |
6 |
$up->add($this->created_by,$this->id); |
7 |
}
|
8 |
}
|
Im UserPlace-Modell fügen wir die Funktion hinzu:
1 |
// add place to user place list
|
2 |
public function add($user_id,$place_id) { |
3 |
// check if it exists
|
4 |
if (!UserPlace::find() |
5 |
->where( [ 'user_id' => $user_id, 'place_id' => $place_id ] ) |
6 |
->exists()) { |
7 |
// if not, add it
|
8 |
$up = new UserPlace; |
9 |
$up->user_id =$user_id; |
10 |
$up->place_id=$place_id; |
11 |
$up->save(); |
12 |
}
|
13 |
}
|
Wenn der Benutzer die Bereichsindexseite besucht, möchten wir nur die von ihm verwendeten Orte anzeigen, nur die in der UserPlace-Tabelle für diesen Benutzer.
Ich werde Sie durch zwei verschiedene Wege führen, um dies zu erreichen. Da ich mit Yii2.x immer noch Erfahrung sammle, waren die Besonderheiten des besten Ansatzes hier neu für mich. Ich möchte Alex Makarov, einem Entwickler von Yii, der auch YiiFeed.com verwaltet, für seine Unterstützung danken. Sowohl er als auch Yii-Gründer Qiang Xue waren sehr hilfreich bei der Beantwortung von Fragen und der Unterstützung meiner Bemühungen mit diesen Yii-bezogenen Tutorials.
Der einfachste Ansatz
Am einfachsten ist es, die Place-Tabelle mit der UserPlace-Tabelle in der UserPlace.place_id
-Eigenschaftsfilterung in UserPlace.user_id
mit dem aktuell authentifizierten Benutzer zu verknüpfen.
Hier ist die Standard-Index-Controller-Methode:
1 |
public function actionIndex() |
2 |
{
|
3 |
$searchModel = new PlaceSearch(); |
4 |
$dataProvider = $searchModel->search(Yii::$app->request->queryParams); |
5 |
|
6 |
return $this->render('index', [ |
7 |
'searchModel' => $searchModel, |
8 |
'dataProvider' => $dataProvider, |
9 |
]);
|
10 |
}
|
Wir erstellen eine neue Controller-Methode namens Yours:
1 |
public function actionYours() |
2 |
{
|
3 |
$query = Place::find()->joinWith('userPlaces')->where(['user_id' => Yii::$app->user->getId()]); |
4 |
$searchModel = new PlaceSearch(); |
5 |
|
6 |
$dataProvider = new ActiveDataProvider([ |
7 |
'query' => $query, |
8 |
'pagination' => ['pageSize' => 10], |
9 |
]);
|
10 |
|
11 |
return $this->render('yours',[ |
12 |
'dataProvider' => $dataProvider, |
13 |
'searchModel'=>$searchModel, |
14 |
]);
|
15 |
}
|
Beachten Sie, dass joinWith('userPlaces')
die von Gii generierte relationale Abfrage in Place.php verwendet. Dies kann etwas verwirrend sein, wenn Sie das Präfix "get" weglassen:
1 |
/**
|
2 |
* @return \yii\db\ActiveQuery
|
3 |
*/
|
4 |
public function getUserPlaces() |
5 |
{
|
6 |
return $this->hasMany(UserPlace::className(), ['place_id' => 'id']); |
7 |
}
|
Wir müssen auch die Klasse PlaceSearch
ändern:
1 |
// add a required rule for created_by |
2 |
public function rules() |
3 |
{ |
4 |
return [ |
5 |
[['created_by'], 'required'], |
6 |
|
7 |
// add the join within the search query |
8 |
public function search($params) |
9 |
{ |
10 |
$query = Place::find()->joinWith('user_place')->where(['user_id' => Yii::$app->user->getId()]); |
11 |
$dataProvider = new ActiveDataProvider([ |
12 |
'query' => $query, |
13 |
]); |
Ein alternativer Ansatz
Eine andere Möglichkeit, dies zu implementieren, ist über einen UserPlace-Controller. Immerhin betrachten wir "die Orte des Benutzers". In diesem Fall können wir die von Gii generierte Controller-Indexmethode geringfügig ändern:
1 |
public function actionIndex() |
2 |
{
|
3 |
$searchModel = new UserPlaceSearch(); |
4 |
$searchModel->user_id = Yii::$app->user->getId(); |
5 |
$dataProvider = $searchModel->search(Yii::$app->request->queryParams); |
6 |
|
7 |
return $this->render('index', [ |
8 |
'searchModel' => $searchModel, |
9 |
'dataProvider' => $dataProvider, |
10 |
]);
|
11 |
}
|
In /views/user-place/index.php
müssen wir dann die generierten Verknüpfungspfade und den Modelldatenzugriff ändern, z. /place/create_place_google
:
1 |
<p>
|
2 |
<?= Html::a(Yii::t('frontend', 'Create {modelClass}', [ |
3 |
'modelClass' => 'Place', |
4 |
]), ['/place/create'], ['class' => 'btn btn-success']) ?> |
5 |
|
6 |
<?= Html::a(Yii::t('frontend','Add Current Location'), ['/place/create_geo'], ['class' => 'btn btn-success']) ?> |
7 |
<?= Html::a(Yii::t('frontend','Add a Google {modelClass}',[ |
8 |
'modelClass' => 'Place' |
9 |
]), ['/place/create_place_google'], ['class' => 'btn btn-success']) ?> |
10 |
</p>
|
Im Widget "Rasteransicht" verwenden wir die UserPlace-Beziehung zur Place-Tabelle, um Eigenschaften des letzteren Modells zu erreichen, z. $model->place->slug
:
1 |
<?= GridView::widget([ |
2 |
'dataProvider' => $dataProvider, |
3 |
//'filterModel' => $searchModel,
|
4 |
'columns' => [ |
5 |
// ['class' => 'yii\grid\SerialColumn'],
|
6 |
|
7 |
[
|
8 |
'attribute' => 'place_name', |
9 |
'format' => 'raw', |
10 |
'value' => function ($model) { |
11 |
return '<div>'.$model->place->name.'</div>'; |
12 |
},
|
13 |
],
|
14 |
[
|
15 |
'attribute' => 'place_type', |
16 |
'format' => 'raw', |
17 |
'value' => function ($model) { |
18 |
return '<div>'.$model->place->getPlaceType($model->place->place_type).'</div>'; |
19 |
},
|
20 |
],
|
21 |
['class' => 'yii\grid\ActionColumn', |
22 |
'template'=>'{view} {update} ', |
23 |
'buttons'=>[ |
24 |
'view' => function ($url, $model) { |
25 |
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', Yii::getAlias('@web').'/place/'.$model->place->slug, ['title' => Yii::t('yii', 'View'),]); |
26 |
},
|
27 |
'update' => function ($url, $model) { |
28 |
return Html::a('<span class="glyphicon glyphicon-pencil"></span>', Yii::getAlias('@web').'/place/update/'.$model->place_id, ['title' => Yii::t('yii', 'Update'),]); |
29 |
}
|
30 |
],
|
31 |
],
|
32 |
],
|
33 |
]); ?> |
Der UserPlace-Ansatz erfordert einige Änderungen an Verknüpfungen rund um Breadcrumbs, Widget-Aktionslinks und Befehlsschaltflächen, ist jedoch immer noch recht einfach.
Wenn Sie den Code in dieser Version überprüfen, können Sie die Orte des Benutzers von beiden Seiten sehen: http://localhost:8888/mp/place/yours und http://localhost:8888/mp/user-place. Es ist interessant zu sehen, wie Sie diese Funktionalität mit zwei verschiedenen Ansätzen in Yii erreichen können.
Slugs
Sobald Sie hübsche URLs im Yii Framework aktiviert haben, handelt es sich bei der Ansichtsseite für ein Modellobjekt in der Regel um http://meetingplanner.com/place/692, wobei 692 die ID des anzuzeigenden Objekts darstellt. Abgesehen davon, dass sie für den Benutzer nicht unauffällig ist, ist er bei Suchmaschinen weniger effektiv. Es empfiehlt sich, URL-freundliche Zeichenfolgen wie http://meetingplanner.com/place/caffe-seattle zu verwenden. Die Zeichenfolge wird manchmal als Slug bezeichnet. Yii2 bietet integrierte Unterstützung für Slugs in Form von Sluggable Behaviors. Verhalten sind Teil der Active Record-Unterstützung von Yii und können automatisch auf Datenobjektmodelle angewendet werden.
In unserem Platzmodell haben wir eine Slug-Eigenschaft hinzugefügt. So implementieren wir Sluggable Behavior im Ortsmodell:
1 |
public function behaviors() |
2 |
{
|
3 |
return [ |
4 |
[
|
5 |
'class' => SluggableBehavior::className(), |
6 |
'attribute' => 'name', |
7 |
'immutable' => true, |
8 |
'ensureUnique'=>true, |
9 |
],
|
Yii stellt während der save()
- Operation sicher, dass das Slug-Feld mit einer URL-freundlichen Version des Namensfelds gefüllt wird. Mit anderen Worten, wenn der Ortsname Oddfellows Cafe ist, wird der Slug oddfellows-cafe sein.
Die unveränderliche Eigenschaft stellt sicher, dass sich der Slug nicht ändert, selbst wenn der Anzeigename bearbeitet wird. Dies ist nützlich, um Links zu Orten sowie Suchmaschinenreferenzen zu erhalten.
Die Eigenschaft sureUnique generiert einen eindeutigen Slug, indem automatisch ein Suffixindex angehängt wird.
Yiis automatisierter Codegenerator Gii verknüpft Objekte typischerweise über numerische IDs. Wir möchten diese Links ändern, um den Slug zu verwenden. Es gibt zwei Stellen, an denen dieser Code existiert.
Die erste befindet sich auf der Ortsindexseite in den Rasteraktionsspalten. Sie können diese Links in /frontend/views/places/index.php
wie folgt anpassen:
1 |
<?= GridView::widget([ |
2 |
'dataProvider' => $dataProvider, |
3 |
'filterModel' => $searchModel, |
4 |
'columns' => [ |
5 |
['class' => 'yii\grid\SerialColumn'], |
6 |
'name', |
7 |
[
|
8 |
'attribute' => 'place_type', |
9 |
'format' => 'raw', |
10 |
'value' => function ($model) { |
11 |
return '<div>'.$model->getPlaceType($model->place_type).'</div>'; |
12 |
},
|
13 |
],
|
14 |
['class' => 'yii\grid\ActionColumn', |
15 |
'template'=>'{view} {update} ', |
16 |
'buttons'=>[ |
17 |
'view' => function ($url, $model) { |
18 |
return Html::a('<span class="glyphicon glyphicon-eye-open"></span>', 'place/'.$model->slug, ['title' => Yii::t('yii', 'View'),]); |
19 |
}
|
20 |
],
|
21 |
],
|
22 |
],
|
23 |
]); ?> |
Der andere Ort ist in Brotkrumen:



In /frontend/views/place/update.php
müssen wir beispielsweise Folgendes ändern:
1 |
<?php
|
2 |
|
3 |
use yii\helpers\Html; |
4 |
|
5 |
/* @var $this yii\web\View */
|
6 |
/* @var $model frontend\models\Place */
|
7 |
|
8 |
$this->title = Yii::t('frontend', 'Update {modelClass}: ', [ |
9 |
'modelClass' => 'Place', |
10 |
]) . ' ' . $model->name; |
11 |
$this->params['breadcrumbs'][] = ['label' => Yii::t('frontend', 'Places'), 'url' => ['index']]; |
12 |
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['view', 'id' => $model->id]]; |
13 |
$this->params['breadcrumbs'][] = Yii::t('frontend', 'Update'); |
14 |
?>
|
Ersetzen des Ansichts-ID-Codes zur Verwendung des Slugs:
1 |
...
|
2 |
$this->params['breadcrumbs'][] = ['label' => Yii::t('frontend', 'Places'), 'url' => ['index']]; |
3 |
$this->params['breadcrumbs'][] = ['label' => $model->name, 'url' => ['slug', 'slug' => $model->slug]]; |
4 |
$this->params['breadcrumbs'][] = Yii::t('frontend', 'Update'); |
5 |
...
|
Aufräumen und Polnisch
Beim Erstellen von Meeting Planner wird es Code-Sprints geben, um neue Funktionen und Zeiträume zu erstellen, die für die Bereinigung und Aufbereitung benötigt werden. Dies ist wahrscheinlich ein sich wiederholender Zyklus.
Ich werde ein paar Szenarien durchgehen, die ich zu diesem Zeitpunkt behandeln möchte. Natürlich werden auch weiterhin Bereinigungsbereiche erforderlich sein, solange wir Code erstellen, das Feedback der Benutzer aufnehmen und das Produkt verbessern.
Navigationsleiste erweitern
Yii2 ist gut in Bootstrap integriert, sodass Ihre Anwendungen gut aussehen und sofort einsatzbereit sind. Wenn Sie eine Navigationsleiste mit Dropdown-Menüs erstellen möchten, ist es hilfreich, wenn Sie die Bootstrap-Dokumentation lesen und die Verwendung von Short Array-Notation in Yii2 in PHP verstehen. Die Yii2 Navbar Widget-Dokumentation enthält zurzeit keine Beispiele.
Ich beschloss, die Meeting Planner-Navigation mit einigen Dropdown-Menüs basierend auf dem Benutzerstatus zu aktualisieren, z. Gast oder authentifiziert.



Hier ist der Code, der das obige implementiert - ich bin mir sicher, dass ich ihn weiter modifizieren werde:
1 |
NavBar::begin([ |
2 |
'brandLabel' => Yii::t('frontend','MeetingPlanner.io'), // |
3 |
'brandUrl' => Yii::$app->homeUrl, |
4 |
'options' => [ |
5 |
'class' => 'navbar-inverse navbar-fixed-top', |
6 |
],
|
7 |
]);
|
8 |
if (Yii::$app->user->isGuest) { |
9 |
$menuItems[] = ['label' => Yii::t('frontend','Signup'), 'url' => ['/site/signup']]; |
10 |
$menuItems[] = ['label' => Yii::t('frontend','Login'), 'url' => ['/site/login']]; |
11 |
} else { |
12 |
$menuItems = [ |
13 |
['label' => Yii::t('frontend','Places'), 'url' => ['/place/yours']], |
14 |
];
|
15 |
}
|
16 |
$menuItems[]=['label' => Yii::t('frontend','About'), |
17 |
'items' => [ |
18 |
['label' => Yii::t('frontend','Learn more'), 'url' => ['/site/about']], |
19 |
['label' => Yii::t('frontend','Contact'), 'url' => ['/site/contact']], |
20 |
],
|
21 |
];
|
22 |
if (!Yii::$app->user->isGuest) { |
23 |
$menuItems[] = [ |
24 |
'label' => 'Account', |
25 |
'items' => [ |
26 |
[
|
27 |
'label' => Yii::t('frontend','Contact information'), |
28 |
'url' => ['/user-contact'], |
29 |
],
|
30 |
[
|
31 |
'label' => Yii::t('frontend','Logout').' (' . Yii::$app->user->identity->username . ')', |
32 |
'url' => ['/site/logout'], |
33 |
'linkOptions' => ['data-method' => 'post'] |
34 |
],
|
35 |
],
|
36 |
];
|
37 |
}
|
38 |
echo Nav::widget([ |
39 |
'options' => ['class' => 'navbar-nav navbar-right'], |
40 |
'items' => $menuItems, |
41 |
]);
|
42 |
NavBar::end(); |
Modelle vor dem Speichern richtig validieren
Ich habe die Erstellungsaktionen in PlaceController umgeschrieben, um die Modelle zu überprüfen, bevor wir versuchen, UserPlace-Beziehungen hinzuzufügen. Es gab einige Fälle, in denen ungültige Daten übermittelt werden konnten, und dies würde den Versuch unterbrechen, Beziehungen hinzuzufügen. Dadurch wird auch sichergestellt, dass Benutzer bei fehlgeschlagenen Validierungen mit freundlichen Fehlermeldungen zum Formular zurückkehren.
1 |
public function actionCreate() |
2 |
{ |
3 |
$model = new Place(); |
4 |
if ($model->load(Yii::$app->request->post())) { |
5 |
$form = Yii::$app->request->post(); |
6 |
if (!is_numeric($model->place_type)) { |
7 |
$model->place_type=Place::TYPE_OTHER; |
8 |
} |
9 |
$model->created_by= Yii::$app->user->getId(); |
10 |
// validate the form against model rules |
11 |
if ($model->validate()) { |
12 |
// all inputs are valid |
13 |
$model->save(); |
14 |
// lookup gps location from address |
15 |
$model->addLocationFromAddress($model,$form['Place']['full_address']); |
16 |
return $this->redirect(['view', 'id' => $model->id]); |
17 |
} else { |
18 |
// validation failed |
19 |
return $this->render('create', [ |
20 |
'model' => $model, |
21 |
]); |
22 |
} |
23 |
} else { |
24 |
return $this->render('create', [ |
25 |
'model' => $model, |
26 |
]); |
27 |
} |
28 |
} |
Duplikate vermeiden
In unserem ursprünglichen Erstellungscode möchten wir uns vor Duplikaten schützen. Orte können identische Namen haben, z. Es gibt viele Starbucks-Kaffees (viel zu viele), aber wir möchten verhindern, dass der genaue Ort zweimal erstellt wird, z. Starbucks Coffee mit identischer Google Place-ID oder identischem Namen und Straße.
Yii bietet Modellvalidatoren an, die in ActiveForms integriert sind, um einen Großteil dieser Arbeit für uns zu erledigen. Hier sind die Regeln, die wir im Platzmodell definieren:
1 |
/**
|
2 |
* @inheritdoc
|
3 |
*/
|
4 |
public function rules() |
5 |
{
|
6 |
return [ |
7 |
[['name','slug'], 'required'], |
8 |
[['place_type', 'status', 'created_by', 'created_at', 'updated_at'], 'integer'], |
9 |
[['name', 'google_place_id', 'slug', 'website', 'full_address', 'vicinity'], 'string', 'max' => 255], |
10 |
[['website'], 'url'], |
11 |
[['slug'], 'unique'], |
12 |
[['searchbox'], 'unique','targetAttribute' => 'google_place_id'], |
13 |
[['name', 'full_address'], 'unique', 'targetAttribute' => ['name', 'full_address']], |
14 |
];
|
15 |
}
|
Prüfer können erforderliche Felder und Feldtypen sowie deren Länge erzwingen. Sie können auch URLs überprüfen, z. B. mit dem Website-Feld, E-Mail-Adressen und mehr. Sie können auch benutzerdefinierte Prüfer schreiben.
Es gibt mehrere eingebaute Validatoren, die für die Eindeutigkeit spezifisch sind. Sie können beispielsweise die Eindeutigkeit einzelner Felder überprüfen, wie wir es mit dem Slug-Feld getan haben. Es gibt aber auch komplexere Eindeutigkeitsprüfer.
Wenn der Nutzer einen Ort mit Google Autocomplete hinzufügt, möchten wir die Eindeutigkeit der resultierenden google_place_id
im ausgeblendeten Feld erzwingen. Die Fehlermeldung wird jedoch im Feld searchbox
angezeigt. Diese Definition erfüllt es:
1 |
[['searchbox'], 'unique','targetAttribute' => 'google_place_id'], |
Wir möchten auch sicherstellen, dass Name und Adresse zusammen eindeutig sind. Mit anderen Worten, mehrere Orte können denselben Namen oder dieselbe Adresse haben, aber in beiden Feldern darf kein Ort identisch sein. Diese Definition tut das:
1 |
[['name', 'full_address'], 'unique', 'targetAttribute' => ['name', 'full_address']], |
Natürlich können viele Benutzer ihrer UserPlaces-Liste denselben Ort hinzufügen.
Löschen wird gestrichen
Ich möchte auch vor dem Löschen von Orten schützen. Yiis automatischer Codegenerator Gii verlinkt normalerweise, um Operationen aus dem Indexraster zu löschen und Seiten zu aktualisieren. Wir wollen diese entfernen. Und wir möchten den Zugriff auf die Löschaktion vom Controller aus einschränken.
Hier ein Beispiel für die Ortsindexseite mit Löschsymbolen:



Wenn wir die Slug-Links oben angepasst haben, haben wir die Verwendung des Löschbefehls standardmäßig entfernt.
Übrigens schätze ich sehr, dass Yiis Bootstrap und die Glyphicons verwendet haben. Sie arbeiten wunderbar.
Hier ist die Ansichtsseite mit der Schaltfläche "Löschen":



Lassen Sie uns zunächst den Code für die Schaltfläche "Löschen" in /frontend/views/place/view.php
auskommentieren. Vielleicht möchten wir es für Administratoren irgendwann wieder hinzufügen.
1 |
<?php /* Html::a(Yii::t('frontend', 'Delete'), ['delete', 'id' => $model->id], [ |
2 |
'class' => 'btn btn-danger',
|
3 |
'data' => [
|
4 |
'confirm' => Yii::t('frontend', 'Are you sure you want to delete this item?'),
|
5 |
'method' => 'post',
|
6 |
],
|
7 |
]) */ ?> |
Autovervollständigung verhindern Geben Sie die Schlüsselübergabe ein
Beim Erstellen einiger HTML5-Geolocation- und Google Places-Autocomplete-Codes sind einige Fehler aufgetreten, einige im Zusammenhang mit JavaScript.
Wenn Sie beispielsweise nach der Eingabe in das Feld für die automatische Vervollständigung auf die Eingabetaste klicken, sendet Google das Formular. Wir müssen das überschreiben.
In unserem create_place.js fügen wir einen Schlüsselhandler hinzu, um das Senden des Formulars zu stoppen:
1 |
function setupListeners() { |
2 |
// ...
|
3 |
var place_input = document.getElementById('place-searchbox'); |
4 |
google.maps.event.addDomListener(place_input, 'keydown', function(e) { |
5 |
if (e.keyCode == 13) { |
6 |
e.preventDefault(); |
7 |
}
|
8 |
});
|
9 |
}
|
Wenn Sie nun die Eingabetaste drücken, wird die Karte auf der Seite angezeigt und Sie können den Rest des Formulars vor dem Senden bearbeiten.



Überprüfen der Vorteile eines Frameworks
Viele Leute meinen, PHP sei eine weniger seriöse oder fähige Plattform, auf der man aufbauen kann. Für mich hat der Erfolg von Facebook mit PHP für immer bewiesen, dass es falsch ist.
Viele Leute haben nicht vom Yii-Framework gehört oder den Wert von Frameworks verworfen.
Kurz in dieser Startup-Serie haben wir bereits von einer Vielzahl von Yiis Framework-Funktionen profitiert: Beschleunigung der Entwicklung, Bereitstellung einer sauberen Architektur und Qualitätscode:
- MVC-Architektur
- Datenbankmigrationen
- Active Record Modellbeziehungen und Validierung
- automatisierte Codegenerierung
- Bootstrap-Integration und Glyphicons
- Zugriffssteuerungsfilter
- Slug-Verhalten
- internationalization
Aus diesem Grund bin ich ein großer Befürworter des Yii-Frameworks. Das hat mich zu einem viel effizienteren Entwickler gemacht, der Lösungen schneller als mit Vanilla PHP liefern kann.
Was kommt als nächstes?
Im nächsten Abschnitt Erstellen Sie Ihr Startup mit PHP-Tutorial bauen wir die Unterstützung für Benutzereinstellungen, Kontakte und Profilbilder aus.
Bitte zögern Sie nicht, Ihre Fragen und Kommentare unten hinzuzufügen. Ich nehme generell an den Diskussionen teil. Sie können mich auch auf Twitter @reifman erreichen oder mich direkt per E-Mail kontaktieren.