Skip to content

Commit 9379e73

Browse files
josbeirCopilot
andauthored
Clean up and modernize quickstart guide (#8166)
* Clean up and modernize quickstart guide * Reference get-help from homepage * Update docs/en/tutorials-and-examples/cms/articles-controller.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Add callout about password hashing --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
1 parent a0d880b commit 9379e73

File tree

6 files changed

+397
-189
lines changed

6 files changed

+397
-189
lines changed

docs/en/quickstart.md

Lines changed: 71 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,52 @@
11
# Quick Start Guide
22

33
The best way to experience and learn CakePHP is to sit down and build something.
4-
To start off we'll build a simple Content Management application.
4+
In this tutorial, we'll build a simple **Content Management System (CMS)** application that demonstrates the core features of CakePHP.
5+
6+
## What You'll Build
7+
8+
By the end of this tutorial, you'll have a fully functional CMS with:
9+
10+
-**User Authentication** - Secure login system
11+
-**Article Management** - Create, read, update, and delete articles
12+
-**Tag System** - Organize content with tags
13+
-**Database Relations** - Users, articles, and tags working together
14+
-**Form Validation** - Input validation and error handling
15+
-**Clean URLs** - SEO-friendly slug-based routing
16+
17+
::: tip Estimated Time
18+
This tutorial takes approximately **45-60 minutes** to complete from start to finish.
19+
:::
20+
21+
## What You'll Learn
22+
23+
This hands-on tutorial covers:
24+
25+
- Setting up a CakePHP application
26+
- Database migrations and schema management
27+
- Creating models with the ORM
28+
- Building controllers and actions
29+
- Rendering views and templates
30+
- Form handling and validation
31+
- Authentication and authorization
32+
- Working with associations (relationships)
33+
34+
::: details Prerequisites
35+
Before starting, make sure you have:
36+
37+
| Requirement | Version |
38+
|-------------|---------|
39+
| PHP | |minphpversion| - |phpversion| |
40+
| Composer | Latest |
41+
| Database | MySQL 5.7+, PostgreSQL 9.6+, or SQLite 3 |
42+
| Web Server | PHP built-in server (for development) |
43+
44+
**Basic PHP knowledge is recommended** but not strictly required.
45+
:::
46+
47+
## Getting Started
48+
49+
Let's begin by installing CakePHP and setting up your development environment.
550

651
<!--@include: tutorials-and-examples/cms/installation.md-->
752

@@ -10,3 +55,28 @@ To start off we'll build a simple Content Management application.
1055
<!--@include: tutorials-and-examples/cms/articles-model.md-->
1156

1257
<!--@include: tutorials-and-examples/cms/articles-controller.md-->
58+
59+
## What's Next?
60+
61+
🎉 **Congratulations!** You've built your first CakePHP application and learned the fundamentals of the framework.
62+
63+
### Continue Building
64+
65+
Ready to enhance your CMS? Here are some features you could add next:
66+
67+
- **[Authentication & Authorization](../tutorials-and-examples/cms/authentication)** - Secure your application with user login
68+
- **[Tags & Categories](../tutorials-and-examples/cms/tags-and-users)** - Add tagging functionality to organize articles
69+
70+
### Explore CakePHP Features
71+
72+
Dive deeper into CakePHP's powerful features:
73+
74+
- **[ORM & Database](../orm)** - Advanced queries, associations, and behaviors
75+
- **[Validation](../core-libraries/validation)** - Complex validation rules and custom validators
76+
- **[Security](../security)** - CSRF protection, encryption, and security best practices
77+
- **[Testing](../development/testing)** - Write unit and integration tests
78+
- **[Deployment](../deployment)** - Deploy your application to production
79+
80+
### Get Help & Connect
81+
82+
<!--@include: index.md#get-help-->

docs/en/tutorials-and-examples/cms/articles-controller.md

Lines changed: 53 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ methods, to prepare the response. We'll place this new controller in a file
66
called **ArticlesController.php** inside the **src/Controller** directory.
77
Here's what the basic controller should look like:
88

9-
``` php
9+
``` php {3}
1010
<?php
1111
// src/Controller/ArticlesController.php
12+
declare(strict_types=1);
1213

1314
namespace App\Controller;
1415

@@ -25,15 +26,16 @@ have routes connected to them. For example, when a user requests
2526
a response by rendering a Template in the View. The code for that action would
2627
look like this:
2728

28-
``` php
29+
``` php {3,9}
2930
<?php
3031
// src/Controller/ArticlesController.php
32+
declare(strict_types=1);
3133

3234
namespace App\Controller;
3335

3436
class ArticlesController extends AppController
3537
{
36-
public function index()
38+
public function index(): void
3739
{
3840
$articles = $this->paginate($this->Articles);
3941
$this->set(compact('articles'));
@@ -126,10 +128,10 @@ correctly formatted with the title and table listing of the articles.
126128
If you were to click one of the 'view' links in our Articles list page, you'd
127129
see an error page saying that action hasn't been implemented. Lets fix that now:
128130

129-
``` php
131+
``` php {3}
130132
// Add to existing src/Controller/ArticlesController.php file
131133

132-
public function view($slug = null)
134+
public function view(?string $slug): void
133135
{
134136
$article = $this->Articles->findBySlug($slug)->firstOrFail();
135137
$this->set(compact('article'));
@@ -153,7 +155,7 @@ page telling us we're missing a view template; let's fix that.
153155
Let's create the view for our new 'view' action and place it in
154156
**templates/Articles/view.php**
155157

156-
``` php
158+
``` php {3-4}
157159
<!-- File: templates/Articles/view.php -->
158160

159161
<h1><?= h($article->title) ?></h1>
@@ -162,6 +164,10 @@ Let's create the view for our new 'view' action and place it in
162164
<p><?= $this->Html->link('Edit', ['action' => 'edit', $article->slug]) ?></p>
163165
```
164166

167+
::: tip Security: XSS Protection
168+
The `h()` helper function escapes output to prevent XSS (Cross-Site Scripting) attacks. Always use it when outputting user-generated content.
169+
:::
170+
165171
You can verify that this is working by trying the links at `/articles/index` or
166172
manually requesting an article by accessing URLs like
167173
`/articles/view/first-post`.
@@ -172,28 +178,30 @@ With the basic read views created, we need to make it possible for new articles
172178
to be created. Start by creating an `add()` action in the
173179
`ArticlesController`. Our controller should now look like:
174180

175-
``` php
181+
``` php {3,11,17,23}
176182
<?php
177183
// src/Controller/ArticlesController.php
184+
declare(strict_types=1);
185+
178186
namespace App\Controller;
179187

180188
use App\Controller\AppController;
181189

182190
class ArticlesController extends AppController
183191
{
184-
public function index()
192+
public function index(): void
185193
{
186194
$articles = $this->paginate($this->Articles);
187195
$this->set(compact('articles'));
188196
}
189197

190-
public function view($slug)
198+
public function view(?string $slug): void
191199
{
192200
$article = $this->Articles->findBySlug($slug)->firstOrFail();
193201
$this->set(compact('article'));
194202
}
195203

196-
public function add()
204+
public function add(): void
197205
{
198206
$article = $this->Articles->newEmptyEntity();
199207
if ($this->request->is('post')) {
@@ -215,10 +223,11 @@ class ArticlesController extends AppController
215223
}
216224
```
217225

218-
> [!NOTE]
219-
> You need to include the [Flash](../../controllers/components/flash) component in
220-
> any controller where you will use it. Often it makes sense to include it in
221-
> your `AppController`, which is there already for this tutorial.
226+
::: info Flash Component
227+
You need to include the [Flash](../../controllers/components/flash) component in
228+
any controller where you will use it. Often it makes sense to include it in
229+
your `AppController`, which is there already for this tutorial.
230+
:::
222231

223232
Here's what the `add()` action does:
224233

@@ -304,15 +313,15 @@ creating a slug attribute, and the column is `NOT NULL`. Slug values are
304313
typically a URL-safe version of an article's title. We can use the
305314
[beforeSave() callback](../../orm/table-objects#table-callbacks) of the ORM to populate our slug:
306315

307-
``` php
316+
``` php {3,7-9,13}
308317
<?php
309318
// in src/Model/Table/ArticlesTable.php
319+
declare(strict_types=1);
320+
310321
namespace App\Model\Table;
311322

312323
use Cake\ORM\Table;
313-
// the Text class
314324
use Cake\Utility\Text;
315-
// the EventInterface class
316325
use Cake\Event\EventInterface;
317326

318327
// Add the following method.
@@ -335,12 +344,10 @@ fix that later on.
335344
Our application can now save articles, but we can't edit them. Lets rectify that
336345
now. Add the following action to your `ArticlesController`:
337346

338-
``` php
347+
``` php {3}
339348
// in src/Controller/ArticlesController.php
340349

341-
// Add the following method.
342-
343-
public function edit($slug)
350+
public function edit(?string $slug): void
344351
{
345352
$article = $this->Articles
346353
->findBySlug($slug)
@@ -430,11 +437,11 @@ articles:
430437
Up until this point our Articles had no input validation done. Lets fix that by
431438
using [a validator](../../orm/validation#validating-request-data):
432439

433-
``` php
440+
``` php {5,8}
434441
// src/Model/Table/ArticlesTable.php
435442

436-
// add this use statement right below the namespace declaration to import
437-
// the Validator class
443+
// add this use statement right below the namespace declaration
444+
// to import the Validator class
438445
use Cake\Validation\Validator;
439446

440447
// Add the following method.
@@ -472,12 +479,10 @@ automatically.
472479
Next, let's make a way for users to delete articles. Start with a
473480
`delete()` action in the `ArticlesController`:
474481

475-
``` php
482+
``` php {3}
476483
// src/Controller/ArticlesController.php
477484

478-
// Add the following method.
479-
480-
public function delete($slug)
485+
public function delete(?string $slug): void
481486
{
482487
$this->request->allowMethod(['post', 'delete']);
483488

@@ -499,10 +504,11 @@ error page is displayed. There are many built-in
499504
[Exceptions](../../development/errors) that can be used to indicate the various
500505
HTTP errors your application might need to generate.
501506

502-
> [!WARNING]
503-
> Allowing content to be deleted using GET requests is *very* dangerous, as web
504-
> crawlers could accidentally delete all your content. That is why we used
505-
> `allowMethod()` in our controller.
507+
::: danger Security Warning
508+
Allowing content to be deleted using GET requests is *very* dangerous, as web
509+
crawlers could accidentally delete all your content. That is why we used
510+
`allowMethod()` in our controller.
511+
:::
506512

507513
Because we're only executing logic and redirecting to another action, this
508514
action has no template. You might want to update your index template with links
@@ -548,19 +554,21 @@ Using `Cake\View\Helper\FormHelper::deleteLink()` will create a link
548554
that uses JavaScript to do a DELETE request deleting our article.
549555
Prior to CakePHP 5.2 you need to use `postLink()` instead.
550556

551-
> [!NOTE]
552-
> This view code also uses the `FormHelper` to prompt the user with a
553-
> JavaScript confirmation dialog before they attempt to delete an
554-
> article.
555-
556-
> [!TIP]
557-
> The `ArticlesController` can also be built with `bake`:
558-
>
559-
> ``` bash
560-
> /bin/cake bake controller articles
561-
> ```
562-
>
563-
> However, this does not build the **templates/Articles/\*.php** files.
557+
::: info FormHelper Confirmation
558+
This view code also uses the `FormHelper` to prompt the user with a
559+
JavaScript confirmation dialog before they attempt to delete an
560+
article.
561+
:::
562+
563+
::: tip Use Bake to Generate Controllers
564+
The `ArticlesController` can also be built with `bake`:
565+
566+
``` bash
567+
bin/cake bake controller articles
568+
```
569+
570+
However, this does not build the **templates/Articles/\*.php** files.
571+
:::
564572

565573
With a basic articles management setup, we'll create the [basic actions
566574
for our Tags and Users tables](../../tutorials-and-examples/cms/tags-and-users).

docs/en/tutorials-and-examples/cms/articles-model.md

Lines changed: 17 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ They are stored in **src/Model/Table**. The file we'll be creating will be saved
1111
to **src/Model/Table/ArticlesTable.php**. The completed file should look like
1212
this:
1313

14-
``` php
14+
``` php {3,11}
1515
<?php
1616
// src/Model/Table/ArticlesTable.php
1717
declare(strict_types=1);
@@ -36,19 +36,20 @@ By naming our Table object `ArticlesTable`, CakePHP can use naming conventions
3636
to know that our model uses the `articles` table. CakePHP also uses
3737
conventions to know that the `id` column is our table's primary key.
3838

39-
> [!NOTE]
40-
> CakePHP will dynamically create a model object for you if it
41-
> cannot find a corresponding file in **src/Model/Table**. This also means
42-
> that if you accidentally name your file wrong (i.e. articlestable.php or
43-
> ArticleTable.php), CakePHP will not recognize any of your settings and will
44-
> use the generated model instead.
39+
::: info Automatic Model Creation
40+
CakePHP will dynamically create a model object for you if it
41+
cannot find a corresponding file in **src/Model/Table**. This also means
42+
that if you accidentally name your file wrong (i.e. articlestable.php or
43+
ArticleTable.php), CakePHP will not recognize any of your settings and will
44+
use the generated model instead.
45+
:::
4546

4647
We'll also create an Entity class for our Articles. Entities represent a single
4748
record in the database and provide row-level behavior for our data. Our entity
4849
will be saved to **src/Model/Entity/Article.php**. The completed file should
4950
look like this:
5051

51-
``` php
52+
``` php {3,11}
5253
<?php
5354
// src/Model/Entity/Article.php
5455
declare(strict_types=1);
@@ -77,13 +78,14 @@ Right now, our entity is quite slim; we've only set up the `_accessible`
7778
property, which controls how properties can be modified by
7879
[Entities Mass Assignment](../../orm/entities#entities-mass-assignment).
7980

80-
> [!TIP]
81-
> The `ArticlesTable` and `Article` Entity classes can be generated from a
82-
> terminal:
83-
>
84-
> ``` bash
85-
> bin/cake bake model articles
86-
> ```
81+
::: tip Use Bake to Generate Models
82+
The `ArticlesTable` and `Article` Entity classes can be generated from a
83+
terminal:
84+
85+
``` bash
86+
bin/cake bake model articles
87+
```
88+
:::
8789

8890
We can't do much with this model yet. Next, we'll create our first
8991
[Controller and Template](../../tutorials-and-examples/cms/articles-controller)

0 commit comments

Comments
 (0)