## 1. Project Overview & Quickstart (yiisoft/structure-application-components)

# structure-application-components

Open-source repository yiisoft/structure-application-components

### Repository Details
- **Repository:** [yiisoft/structure-application-components](https://github.com/yiisoft/structure-application-components)
- **Primary Language:** Code

*Note: High-volume repository documentation is actively indexed and synchronized by YakaAI.*

## 2. Official Technical Reference & Guides (yiisoft/docs)

## File: README.md

This repository contains source and translations for the official documentation for Yii3 Framework,
a high-performance PHP framework for building modern web applications.

Rendered version could be viewed at [https://yiisoft.github.io/docs/](https://yiisoft.github.io/docs/).

Documentation is logically divided into three big pieces:

- The Definitive Guide, under the `src/guide` which contains primary documentation about using Yii3 as a whole.
- Community Cookbook, under `src/cookbook` which contains various recipes like "how to do X with Yii3".
- Internals, under `src/internals` which are Yii3 team guidelines that are useful to check if you want to understand
  framework more or contribute to it.

Additionally, there are translations under `src/{language code}` for multiple languages. These should not be edited
directly.

## Contributing

We welcome contributions to improve the documentation, including translations.
Please see the [Documentation Guidelines](https://yiisoft.github.io/docs/internals/014-docs.html) for information
on how to contribute.

## License

The documentation is released under the terms of the BSD License.
Please see [`LICENSE`](./LICENSE.md) for more information.

Maintained by [Yii Software](https://www.yiiframework.com/).

## Support the project

[](https://opencollective.com/yiisoft)

## Follow updates

[](https://www.yiiframework.com/)
[](https://twitter.com/yiiframework)
[](https://t.me/yii3en)
[](https://www.facebook.com/groups/yiitalk)
[](https://yiiframework.com/go/slack)

---

## File: src/id/guide/databases/db-migrations.md

# Migrations

During the course of developing and maintaining a database-driven
application, the structure of the database being used evolves just like the
source code does. For example, during the development of an application, a
new table may be found necessary; after the application is deployed to
production, it may be discovered that an index should be created to improve
the query performance; and so on. Because a database structure change often
requires some source code changes, Yii supports the so-called *database
migration* feature that allows you to keep track of database changes in
terms of *database migrations* which are version-controlled together with
the source code.

The following steps show how database migration can be used by a team during
development:

1. Tim creates a new migration (e.g. creates a new table, changes a column
   definition, etc.).
2. Tim commits the new migration into the source control system (e.g. Git,
   Mercurial).
3. Doug updates his repository from the source control system and receives
   the new migration.
4. Doug applies the migration to his local development database, thereby
   synchronizing his database to reflect the changes that Tim has made.

And the following steps show how to deploy a new release with database
migrations to production:

1. Scott creates a release tag for the project repository that contains some
   new database migrations.
2. Scott updates the source code on the production server to the release
   tag.
3. Scott applies any accumulated database migrations to the production
   database.

```mermaid
sequenceDiagram
    participant Tim
    participant VCS as Source control
    participant Doug
    participant LocalDB as Local development database
    participant Scott
    participant ProdServer as Production server
    participant ProdDB as Production database

    Tim->>Tim: Creates a new migration
    Tim->>VCS: Commits the new migration
    Doug->>VCS: Updates his repository and receives the new migration
    Doug->>LocalDB: Applies the migration locally

    Scott->>VCS: Creates a release tag with new migrations
    Scott->>ProdServer: Updates source code to the release tag
    Scott->>ProdDB: Applies accumulated migrations
```

Yii provides a set of migration command line tools that allow you to:

* create new migrations;
* apply migrations;
* revert migrations;
* re-apply migrations;
* show migration history and status.

All these tools are accessible through the command `yii migrate`. In this
section we will describe in detail how to accomplish various tasks using
these tools.

> [!TIP]
> Migrations could affect not only database schema but adjust existing data to fit new schema, create RBAC
hierarchy or clean up cache.

> [!NOTE]
> When manipulating data using a migration you may find that using your Active Record or entity classes
> for this might be useful because some of the logic is already implemented there. Keep in mind however, that in contrast
> to code written in the migrations, whose nature is to stay constant forever, application logic is subject to change.
> So when using Active Record or entity classes in migration code, changes to the logic in the source code
> may accidentally break the existing migrations. For this reason migration code should be kept independent of other
> application logic such.

## Initial configuration

To use migrations, install
[yiisoft/db-migration](https://github.com/yiisoft/db-migration/) package:

```shell
make composer require yiisoft/db-migration
```

Create a directory to store migrations `src/Migration` right in the project
root.

Add the following configuration to `config/common/params.php`:

```php
'yiisoft/db-migration' => [
    'newMigrationNamespace' => 'App\\Migration',
    'sourceNamespaces' => ['App\\Migration'],
],
```

If you want to place migrations elsewhere, you can define the path in
`newMigrationPath`. If your migrations to be applied are from multiple
sources, such as external modules, `sourcePaths` could be used to define
these.

You need a database connection configured as well. See [Working with
databases](../start/databases.md) for an example of configuring it for
PostgreSQL.

## Creating a migration

To create a new empty migration, run the following command:

```sh
make shell
./yii migrate:create <name>
```

The required `name` argument gives a brief description about the new
migration. For example, if the migration is about creating a new table named
*news*, you may use the name `create_news_table` and run the following
command:

```
make shell
./yii migrate:create create_news_table
```


> [!NOTE]
> Because the `name` argument will be used as part of the generated migration class name,
> it should only contain letters, digits, and/or underscore characters.

The above command will create a new PHP class file named
`src/Migration/M251225221906CreateNewsTable.php`.  The file contains the
following code which mainly declares a migration class with the skeleton
code:

```php
<?php

declare(strict_types=1);

namespace App\Migration;

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;

final class M251225221906CreateNewsTable implements RevertibleMigrationInterface
{
    public function up(MigrationBuilder $b): void
    {
        // TODO: Implement the logic to apply the migration.
    }

    public function down(MigrationBuilder $b): void
    {
        // TODO: Implement the logic to revert the migration.
    }
}
```

In the migration class, you are expected to write code in the `up()` method
that makes changes to the database structure.  You may also want to write
code in the `down()` method to revert the changes made by `up()`. The `up()`
method is invoked when you upgrade the database with this migration, while
the `down()` method is invoked when you downgrade the database.  The
following code shows how you may implement the migration class to create a
`news` table:

```php
<?php

declare(strict_types=1);

namespace App\Migration;

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;

final class M251225221906CreateNewsTable implements RevertibleMigrationInterface
{
    public function up(MigrationBuilder $b): void
    {
        $cb = $b->columnBuilder();

        $b->createTable('news', [
            'id' => $cb::uuidPrimaryKey(),
            'title' => $cb::string()->notNull(),
            'content' => $cb::text(),
        ]);
    }

    public function down(MigrationBuilder $b): void
    {
        $b->dropTable('news');
    }
}
```

Migration builder `$b` in the above manages database schema while the column
builder `$cb` manages column types. Both allow using *abstract types*. When
a migration is applied to a particular database, the abstract types will be
translated into the corresponding database physical types and corresponding
SQL to define them.

Methods available in migration builder belong to the following types:

- Raw queries
  - getDb — to get database connection instance.
  - execute — to execute raw SQL query.
- Data
  - insert / update / delete
  - batchInsert
  - upsert
- Tables and views
  - createTable / renameTable / dropTable
  - truncateTable
  - addCommentOnTable / dropCommentFromTable
  - createView / dropView
- Columns
  - addColumn / renameColumn / alterColumn / dropColumn
  - addCommentOnColumn / dropCommentFromColumn
- Keys and indexes
  - addPrimaryKey / dropPrimaryKey
  - addForeignKey / dropForeignKey
  - createIndex / dropIndex

Additionally, there's a `columnBuilder()` which is used to obtain a column
builder as in example above. The builder has static methods that define
various column types:

- Keys
    - primaryKey
    - smallPrimaryKey
    - bigPrimaryKey
    - uuidPrimaryKey
- Boolean
  - boolean
- Numbers
  - bit
  - tinyint
  - smallint
  - integer
  - bigint
  - flat
  - double
  - decimal
- Strings
  - char
  - string
  - text
- Date and time
  - timestamp
  - datetime
  - datetimeWithTimezone
  - time
  - timeWithTimezone
  - date
- Special types
  - money
  - binary
  - uuid
  - array
  - structured
  - json
- enum

All the above methods create a base type which could be adjusted with
additional methods:

- null / notNull
- defaultValue
- unique
- scale / size / unsigned
- primaryKey / autoIncrement
- check
- comment
- computed
- extra
- reference

### Irreversible migrations

Not all migrations are reversible. For example, if the `up()` method deletes
a row of a table, you may not be able to recover this row in the `down()`
method. Sometimes, you may be just too lazy to implement the `down()`,
because it is not very common to revert database migrations. In this case,
you should implement `Yiisoft\Db\Migration\MigrationInterface` that has
`up()` only.


### Transactional migrations

While performing complex DB migrations, it is important to ensure each
migration to either succeed or fail as a whole so that the database can
maintain integrity and consistency. To achieve this goal, it is recommended
that you may enclose the DB operations of each migration in a transaction
automatically by adding `TransactionalMigrationInterface` to `implements` of
your migration.

As a result, if any operation in the `up()` or `down()` method fails, all
prior operations will be rolled back automatically.

> Note: Not all DBMS support transactions. And some DB queries cannot be put into a transaction. For some examples,
please refer to [implicit commit](https://dev.mysql.com/doc/refman/5.7/en/implicit-commit.html).

## Generating a migration

Instead of writing migrations by hand, the command provides a convenient way
generate some of the code.

```shell
make shell
./yii migrate:create -- my_first_table --command=table --fields=name,example --table-comment=my_first_table
```

That would generate the following:

```php
<?php

declare(strict_types=1);

namespace App\Migration;

use Yiisoft\Db\Migration\MigrationBuilder;
use Yiisoft\Db\Migration\RevertibleMigrationInterface;
use Yiisoft\Db\Migration\TransactionalMigrationInterface;

/**
 * Handles the creation of table `my_first_table`.
 */
final class M251227095006CreateMyFirstTableTable implements RevertibleMigrationInterface, TransactionalMigrationInterface
{
    public function up(MigrationBuilder $b): void
    {
        $columnBuilder = $b->columnBuilder();

        $b->createTable('my_first_table', [
            'id' => $columnBuilder::primaryKey(),
            'name',
            'example',
        ]);

        $b->addCommentOnTable('my_first_table', 'my_first_table');
    }

    public function down(MigrationBuilder $b): void
    {
        $b->dropTable('my_first_table');
    }
}
```

Commands available are:

- create - empty migration.
- table - creating a table. Use `--fields` specify a list of fields to
  use. Types could be specified as well such as
  `id:primaryKey,name:string:defaultValue("Alex"),user_id:integer:foreignKey,category_id2:integer:foreignKey(category
  id2)`.
- dropTable - dropping a table.
- addColumn - adding a column.
- dropColumn - dropping a column.
- junction - creating a junction table. Use `--and` specify a second table.

## Applying Migrations

To upgrade a database to its latest structure, you should apply all
available new migrations using the following command:

```
./yii migrate:up
```

This command will list all migrations that have not been applied so far. If
you confirm that you want to apply these migrations, it will run the `up()`
method in every new migration class, one after another, in the order of
their timestamp values. If any of the migrations fails, the command will
quit without applying the rest of the migrations.

For each migration that has been successfully applied, the command will
insert a row into a database table named `migration` to record the
successful application of the migration. This will allow the migration tool
to identify which migrations have been applied and which have not.

Sometimes, you may only want to apply one or a few new migrations, instead
of all available migrations.  You can do so by specifying the number of
migrations that you want to apply when running the command.  For example,
the following command will try to apply the next three available migrations:

```
./yii migrate:up --limit=3
```

## Reverting Migrations

To revert (undo) one or multiple migrations that have been applied before,
you can run the following command:

```
./yii migrate:down            # revert the most recently applied migration
./yii migrate:down --limit=3  # revert the most 3 recently applied migrations
./yii migrate:down --all      # revert all migrations
```

> Note: Not all migrations are reversible. Trying to revert such migrations will cause an error and stop the
entire reverting process.


## Redoing Migrations

Redoing migrations means first reverting the specified migrations and then
applying again. This can be done as follows:

```
./yii migrate:redo            # redo the last applied migration
./yii migrate:redo --limit=3  # redo the last 3 applied migrations
./yii migrate:redo --all      # redo all migrations
```

> Note: If a migration is not reversible, you will not be able to redo it.

## Listing Migrations

To list which migrations have been applied and which are not, you may use
the following commands:

```
./yii migrate/history            # showing the last 10 applied migrations
./yii migrate:history --limit=5  # showing the last 5 applied migrations
./yii migrate:history --all      # showing all applied migrations

./yii migrate:new                # showing the first 10 new migrations
./yii migrate:new --limit=5      # showing the first 5 new migrations
./yii migrate:new --all          # showing all new migrations
```

### Upgrading from Yii 2.0

Migrations in Yii 2.0 and the
[yiisoft/db-migration](https://github.com/yiisoft/db-migration/) package are
not compatible, and the `migration` table is also not compatible.

A probable solution is to use structure dumps and rename the old `migration`
table. Upon the initial execution of migrations, a new `migration` table
with new fields will be created. All further changes in the database schema
are applied using the new `migration` component and recorded in the new
migration table.

---

## File: src/id/guide/concept/aliases.md

# Aliases

Anda dapat menggunakan alias untuk merepresentasikan path file atau URL
sehingga Anda tidak perlu menulis path absolut atau URL secara hard-code di
proyek Anda. Sebuah alias harus diawali karakter `@` agar dapat dibedakan
dari path file dan URL biasa. Alias yang
didefinisikan tanpa `@` di awal akan diprefiks otomatis dengan karakter `@`.

Aplikasi Yii bawaan memiliki beberapa alias yang sudah didefinisikan di
`config/params.php`. Misalnya, alias `@public` merepresentasikan
path web root; `@baseUrl` merepresentasikan URL dasar untuk aplikasi Web
yang sedang berjalan.

## Defining aliases

Anda dapat mendefinisikan sebuah alias melalui `config/params.php` aplikasi:

```php
return [
    // ...
    
    'yiisoft/aliases' => [
        'aliases' => [
            // ...
        
            // an alias of a file path
            '@foo' => '/path/to/foo',
        
            // an alias of a URL
            '@bar' => 'https://www.example.com',
        
            // an alias of a concrete file that contains a \foo\Bar class 
            '@foo/Bar.php' => '/definitely/not/foo/Bar.php',
        ],
    ],
];
```

> [!NOTE]
> Path file atau URL yang dialias tidak harus selalu merujuk pada file atau sumber daya yang benar-benar ada.

Dengan alias yang telah didefinisikan, Anda dapat menurunkan alias baru
dengan menambahkan garis miring `/` diikuti satu atau beberapa segmen path.
Sebagai contoh, `@foo` adalah alias akar (root), sedangkan
`@foo/bar/file.php` adalah alias turunan.

Anda dapat mendefinisikan sebuah alias menggunakan alias lain (baik alias
akar maupun turunan):

```php
'@foobar' => '@foo/bar',
```

The `yiisoft/aliases` parameter initializes `Aliases` service from
[`yiisoft/aliases`](https://github.com/yiisoft/aliases) package.  You can
set extra aliases in runtime by using the service:

```php
use \Yiisoft\Aliases\Aliases;

public function actionIndex(Aliases $aliases)
{
    $aliases->set('@uploads', '@root/uploads');
}
```

## Using aliases in configuration

Disarankan untuk me-resolve alias pada level konfigurasi, sehingga service
menerima URL dan path sebagai string siap pakai:

```php
<?php

declare(strict_types=1);

use Yiisoft\Aliases\Aliases;
use Yiisoft\Cache\File\FileCache;

/* @var $params array */

return [
    FileCache::class => static fn (Aliases $aliases) => new FileCache(
        $aliases->get($params['yiisoft/cache-file']['fileCache']['path'])
    ),
];
```

## Resolving aliases

Anda dapat menggunakan layanan `Aliases`:

```php
use \Yiisoft\Aliases\Aliases;

public function actionIndex(Aliases $aliases)
{
    $foo = $aliases->get('@foo'); // /path/to/foo
    $bar = $aliases->get('@bar'); // https://www.example.com
    $file = $aliases->get('@foo/bar/file.php'); // /path/to/foo/bar/file.php
}
```

Path/URL yang direpresentasikan oleh alias turunan ditentukan dengan
mengganti bagian alias akar dengan path/URL yang sesuai
pada alias turunan tersebut.

> [!NOTE]
> Metode `get()` tidak memeriksa apakah path/URL hasilnya merujuk pada file atau sumber daya yang ada.


Alias akar juga dapat berisi karakter garis miring `/`. Metode `get()` cukup
cerdas untuk menentukan bagian mana
dari sebuah alias yang merupakan alias akar, sehingga dapat menentukan path
file atau URL yang sesuai dengan benar:

```php
use \Yiisoft\Aliases\Aliases;

public function actionIndex(Aliases $aliases)
{
    $aliases->set('@foo', '/path/to/foo');
    $aliases->set('@foo/bar', '/path2/bar');

    $aliases->get('@foo/test/file.php'); // /path/to/foo/test/file.php
    $aliases->get('@foo/bar/file.php'); // /path2/bar/file.php
} 
```

Jika `@foo/bar` tidak didefinisikan sebagai alias akar, pernyataan terakhir
akan menghasilkan `/path/to/foo/bar/file.php`.


## Predefined aliases

[Aplikasi Yii](https://github.com/yiisoft/app) mendefinisikan serangkaian
alias untuk mereferensikan path file dan URL yang umum digunakan:

- `@root` - direktori dasar dari aplikasi yang sedang berjalan.
- `@assets` - direktori publik aplikasi tempat aset dipublikasikan.
- `@assetsUrl` - URL direktori dasar tempat aset dipublikasikan.
- `@baseUrl` - URL dasar aplikasi Web yang sedang berjalan. Bawaannya `/`.
- `@npm` - direktori paket Node.
- `@bower` - direktori paket bower.
- `@vendor` - direktori `vendor` milik Composer.
- `@public` - direktori publik aplikasi yang berisi `index.php`.
- `@runtime` - path runtime aplikasi yang sedang berjalan. Bawaannya
  `@root/runtime`.
- `@layout` - direktori berkas layout.
- `@resources` - direktori yang berisi view, sumber aset, dan sumber daya
  lainnya.
- `@views` - direktori dasar template view aplikasi.

---

## File: src/id/guide/concept/autoloading.md

# Class autoloading

Karena Yii menggunakan [Composer](https://getcomposer.org) untuk mengelola
paket, Yii secara otomatis memuat kelas dari paket-paket tersebut
tanpa perlu melakukan `require` file-nya secara eksplisit.
Saat Composer memasang paket, ia menghasilkan sebuah [autoloader yang
kompatibel PSR-4](https://www.php-fig.org/psr/psr-4/).
Untuk menggunakannya, lakukan `require_once` terhadap autoloader
`/vendor/autoload.php` di file entry point `index.php` Anda.

Anda dapat menggunakan autoloader tidak hanya untuk paket yang diinstal,
tetapi juga untuk aplikasi Anda sendiri karena aplikasi Anda juga merupakan
sebuah paket.
Untuk memuat kelas-kelas dari namespace tertentu, tambahkan berikut ini ke
`composer.json`:

```json
{
    "autoload": {
        "psr-4": {
            "App\\": "src/"
        }
    }
}
```

Di mana `App\\` adalah namespace akar dan `src/` adalah direktori tempat
kelas-kelas Anda berada. Anda dapat menambahkan lebih banyak sumber (source
roots) jika
diperlukan. Setelah selesai, jalankan `composer dump-autoload` atau cukup
`composer du` dan kelas-kelas dari namespace terkait
akan mulai dimuat secara otomatis.

Jika Anda membutuhkan autoloading khusus lingkungan pengembangan yang tidak
digunakan saat menjalankan Composer dengan flag `--no-dev`,
tambahkan ke bagian `autoload-dev` alih-alih `autoload`.

## Referensi

- [PSR-4: Autoloader](https://www.php-fig.org/psr/psr-4/).
- [Panduan Composer tentang
  autoloading](https://getcomposer.org/doc/01-basic-usage.md#autoloading).

---

## File: src/id/guide/concept/configuration.md

# Konfigurasi

Ada banyak cara untuk mengonfigurasi aplikasi Anda. Kita akan fokus pada
konsep yang digunakan dalam [template proyek
default](https://github.com/yiisoft/app).

Yii3 configs are part of the application. You can change many aspects of how
the application works by editing configuration under `config/` directory.

## Plugin konfigurasi

The application template uses
[yiisoft/config](https://github.com/yiisoft/config) as a composer plugin to
assemble configs.

Packages provide default configurations through defined [config
groups](https://github.com/yiisoft/config#config-groups)  in the
`config-plugin` key in the `extra` section of the `composer.json`:

```json
"extra": {
    "config-plugin-options": {
        "source-directory": "config",
    },
    "config-plugin": {
        "params": "params.php",
        "web": "web.php"
    }
}
```

After Composer updates autoload files, such as during `dump-autoload`,
`install`, `require`, `update`, or `remove`, the plugin scans installed
packages for configurations and writes a merge plan to
`config/.merge-plan.php`.  The merge plan declares the order of merging
found configurations into the final configuration to be passed to [DI
container](di-container.md).

At runtime, `Yiisoft\Config\Config` loads the defined config groups
according to that merge plan.  Configs are read in three layers:

1. Vendor package configs with default values.
2. Root package configs from the application `config/` directory.
3. Environment-specific configs from the application.

> [!WARNING]
> Config keys with the same name are not allowed within a single layer.

The application template stores configurations in a PHP file instead of
inline JSON:

```json
"extra": {
    "config-plugin-file": "config/configuration.php"
}
```

That file returns the same keys you could otherwise define in
`composer.json`: `config-plugin`, `config-plugin-options`, and
`config-plugin-environments`.

```php
use App\Environment;

return [
    'config-plugin-options' => [
        'source-directory' => 'config',
    ],
    'config-plugin' => [
        'params' => 'common/params.php',
        'params-web' => [
            '$params',
            'web/params.php',
        ],
        'params-console' => [
            '$params',
            'console/params.php',
        ],
        'bootstrap' => 'common/bootstrap.php',
        'bootstrap-web' => '$bootstrap',
        'bootstrap-console' => '$bootstrap',
        'di' => 'common/di/*.php',
        'di-web' => [
            '$di',
            'web/di/*.php',
        ],
        'di-console' => '$di',
        'di-delegates' => [],
        'di-delegates-console' => '$di-delegates',
        'di-delegates-web' => '$di-delegates',
        'di-providers' => [],
        'di-providers-web' => '$di-providers',
        'di-providers-console' => '$di-providers',
        'events' => [],
        'events-web' => '$events',
        'events-console' => '$events',
        'routes' => 'common/routes.php',
    ],
    'config-plugin-environments' => [
        Environment::DEV => [
            'params' => [
                'environments/dev/params.php',
            ],
        ],
        Environment::TEST => [
            'params' => [
                'environments/test/params.php',
            ],
        ],
        Environment::PROD => [
            'params' => [
                'environments/prod/params.php',
            ],
        ],
    ],
];
```

Config group names are mapping keys. Their values are file paths relative to
the `source-directory` option, which defaults to the directory containing
`composer.json`.

- A string value loads one file.
- An array loads and merges multiple files in the given order.
- `?` marks an optional file.
- `*` marks a wildcard path.
- `$group` references another config group to be merged.

The `params` group is special: its values are available as `$params` in
other config files by default.

You can read more in the [yiisoft/config
documentation](https://github.com/yiisoft/config/blob/master/README.md).

## Berkas konfigurasi

Now, as you know how the plugin assembles configs, look at the `config/`
directory structure used by the default application template:

```
common/
    bootstrap.php
    params.php
    routes.php
    di/
        *.php
console/
    params.php
environments/
    dev/
        params.php
    prod/
        params.php
    test/
        params.php
web/
    params.php
    di/
        *.php
.merge-plan.php
configuration.php
```

This structure follows the groups defined in `config/configuration.php`:

- `params`, `params-web`, and `params-console` load parameter files from
  `common/`, `web/`, and `console/`.
- `di` and `di-web` load container definitions from `common/di/` and
  `web/di/`.
- `routes` and `bootstrap` load `common/routes.php` and
  `common/bootstrap.php`.
- `config-plugin-environments` adds environment-specific parameter files
  from `environments/dev/`, `environments/test/`, and `environments/prod/`.

At runtime, `.merge-plan.php` stores the assembled merge plan generated from
`configuration.php`.

### Konfigurasi container

The application consists of services registered in a [dependency
container](di-container.md). In the default template, direct container
definitions live in `config/common/di/*.php` and `config/web/di/*.php`.

Definitions from `common/di/` are shared by web and console entry
points. The `di-web` group adds web-specific definitions from `web/di/`. The
`di-console` group currently reuses the shared `di` definitions without
extra files.

```php
<?php

declare(strict_types=1);

use App\Shared\ApplicationParams;

/** @var array $params */

return [
    ApplicationParams::class => [
        '__construct()' => [
            'name' => $params['application']['name'],
            'charset' => $params['application']['charset'],
            'locale' => $params['application']['locale'],
        ],
    ],
];
```

Config plugin passes the special `$params` variable to all config files. The
definition uses it to configure services.

Panduan tentang ["Dependency injection and container"](di-container.md)
menjelaskan format konfigurasi dan gagasan dependency injection secara
rinci.

Untuk kenyamanan, ada konvensi penamaan untuk kunci string kustom:

1. Awali dengan nama paket seperti `yiisoft/cache-file/custom-definition`.
2. Jika konfigurasi untuk aplikasi itu sendiri, lewati prefiks paket,
   mis. `custom-definition`.

### Service provider

As an alternative to registering dependencies directly, you can use service
providers. A service provider is a class that returns a reusable set of
container definitions and extensions.

The default template exposes three config groups for service providers:
`di-providers`, `di-providers-web`, and `di-providers-console`. In the
template they are initialized as empty arrays in `config/configuration.php`,
and you can later populate them inline or switch them to load values from
files.

Prefer direct container configuration for application services with a simple
definition: a class name, an interface implementation, constructor arguments
from `$params`, or a closure that creates a single service.

Use a service provider when the registration itself is a reusable unit:

- A package registers several related services, aliases, or extensions.
- A service registration also needs supporting definitions.
- The same registration should be reused in several applications.
- Registration depends on optional classes or environment-specific
  decisions.

Use a factory class when construction logic belongs to one service. A
factory returns an object. A service provider returns definitions for
several related services.

```php
/* @var array $params */

// ...
use App\Provider\CacheProvider;
use App\Provider\MiddlewareProvider;
// ...

return [
    // ...
    'yiisoft/yii-web/middleware' => MiddlewareProvider::class,
    'yiisoft/cache/cache' => new CacheProvider($params['yiisoft/cache-file']['file-cache']['path']),
    // ...
];
```

In this config keys are provider names. By convention these are
`vendor/package-name/provider-name`. Values are provider class names or
provider instances. These classes could be either created in the project
itself or provided by a package.

Jika Anda perlu mengonfigurasi beberapa opsi untuk sebuah layanan, mirip
dengan konfigurasi container langsung, ambil nilai dari `$params` dan
teruskan ke provider.

Provider should implement `Yiisoft\Di\ServiceProviderInterface`. Below is a
provider for a cache service:

```php
use Psr\Container\ContainerInterface;
use Psr\SimpleCache\CacheInterface;
use Yiisoft\Aliases\Aliases;
use Yiisoft\Cache\Cache;
use Yiisoft\Cache\CacheInterface as YiiCacheInterface;
use Yiisoft\Cache\File\FileCache;
use Yiisoft\Di\ServiceProviderInterface;

final readonly class CacheProvider implements ServiceProviderInterface
{
    public function __construct(
        private string $cachePath = '@runtime/cache'
    )
    {
    }

    public function getDefinitions(): array
    {
        return [
            CacheInterface::class => function (ContainerInterface $container) {
                $aliases = $container->get(Aliases::class);

                return new FileCache($aliases->get($this->cachePath));
            },
            YiiCacheInterface::class => Cache::class,
        ];
    }

    public function getExtensions(): array
    {
        return [];
    }
}
```

### Rute

You can configure how the web application responds to certain URLs in
`config/common/routes.php`:

```php
use App\Web;
use Yiisoft\Router\Group;
use Yiisoft\Router\Route;

return [
    Group::create()
        ->routes(
            Route::get('/')
                ->action(Web\HomePage\Action::class)
                ->name('home'),
        ),
];
``` 

Baca lebih lanjut tentang ini di ["Routes"](../runtime/routing.md).

### Event

Many services emit certain events that you can attach to.  The default
template defines three event config groups in `config/configuration.php`:
`events`, `events-web`, and `events-console`. They are empty by default, but
you can populate them inline or point them to event config files.

The configuration is an array where keys are event names and values are
arrays of handlers:

```php
return [
    EventName::class => [
        // Just a regular closure, it will be called from the Dispatcher "as is".
        static fn (EventName $event) => someStuff($event),
        
        // A regular closure with an extra dependency. All the parameters after the first one (the event itself)
        // will be resolved from your DI container within `yiisoft/injector`.
        static fn (EventName $event, DependencyClass $dependency) => someStuff($event),
        
        // An example with a regular callable. If the `staticMethodName` method has some dependencies,
        // they will be resolved the same way as in the earlier example.
        [SomeClass::class, 'staticMethodName'],
        
        // Non-static methods are allowed too. In this case, `SomeClass` will be instantiated by your DI container.
        [SomeClass::class, 'methodName'],
        
        // An object of a class with the `__invoke` method implemented
        new InvokableClass(),
        
        // In this case, the `InvokableClass` with the `__invoke` method will be instantiated by your DI container
        InvokableClass::class,
        
        // Any invokable class definition may be here as long as `$container->has('the definition')` is true.
        'di-alias'
    ],
];
```

Baca lebih lanjut di ["Events"](events.md).


### Parameter

Base parameters are stored in `config/common/params.php`. They are then
extended by `config/web/params.php`, `config/console/params.php`, and
environment-specific files under `config/environments/`.

> [!TIP]
> Don't use parameters, constants, or environment variables directly in your application, configure
> services instead.

The default application `common/params.php` looks like the following:

```php
<?php

declare(strict_types=1);

use App\Shared\ApplicationParams;
use Yiisoft\Aliases\Aliases;
use Yiisoft\Assets\AssetManager;
use Yiisoft\Definitions\Reference;
use Yiisoft\Router\CurrentRoute;
use Yiisoft\Router\UrlGeneratorInterface;
use Yiisoft\Yii\View\Renderer\CsrfViewInjection;

return [
    'application' => require __DIR__ . '/application.php',

    'yiisoft/aliases' => [
        'aliases' => require __DIR__ . '/aliases.php',
    ],

    'yiisoft/view' => [
        'basePath' => null,
        'parameters' => [
            'assetManager' => Reference::to(AssetManager::class),
            'applicationParams' => Reference::to(ApplicationParams::class),
            'aliases' => Reference::to(Aliases::class),
            'urlGenerator' => Reference::to(UrlGeneratorInterface::class),
            'currentRoute' => Reference::to(CurrentRoute::class),
        ],
    ],

    'yiisoft/yii-view-renderer' => [
        'viewPath' => null,
        'layout' => '@src/Web/Shared/Layout/Main/layout.php',
        'injections' => [
            Reference::to(CsrfViewInjection::class),
        ],
    ],
];
```

Untuk kenyamanan, ada konvensi penamaan mengenai parameter:

1. Kelompokkan parameter berdasarkan nama paket seperti
   `yiisoft/cache-file`.
2. In case parameters are for the application itself, as in `application`,
   skip package prefix.
3. Jika ada banyak layanan dalam paket, seperti `file-target` dan
   `file-rotator` dalam paket `yiisoft/log-target-file`, kelompokkan
   parameter berdasarkan nama layanan.
4. Gunakan `enabled` sebagai nama parameter agar Anda dapat menonaktifkan
   atau mengaktifkan layanan, mis. `yiisoft/yii-debug`.

### Konfigurasi paket

Config plugin does not copy vendor package configs automatically. It loads
them directly from `vendor/` as the vendor layer and combines them with the
root package and environment-specific layers.

If you want to customize a package config file in your application, use the
`yii-config-copy` Composer command to copy it into your `config/` directory,
usually under `config/packages/`. Once copied, the file becomes part of the
root package layer, so it can override vendor defaults.

The merge plan stored in `.merge-plan.php` defines how config groups are
assembled. If you add new config files or directories and update the root
package configuration, rebuild the merge plan with `composer
yii-config-rebuild`.

---

## File: src/id/guide/concept/di-container.md

# Dependency injection and container

## Dependency injection

There are two ways of re-using things in OOP: inheritance and composition.

Inheritance is simple:

```php
class Cache
{
    public function getCachedValue($key)
    {
        // ..
    }
}

final readonly class CachedWidget extends Cache
{
    public function render(): string
    {
        $output = $this->getCachedValue('cachedWidget');
        if ($output !== null) {
            return $output;
        }
        // ...        
    }
}
```

The issue here is that these two are becoming unnecessarily coupled or
inter-dependent, making them more fragile.

Another way to handle this is composition:

```php
interface CacheInterface
{
    public function getCachedValue($key);
}

final readonly class Cache implements CacheInterface
{
    public function getCachedValue($key)
    {
        // ..
    }
}

final readonly class CachedWidget
{
    public function __construct(
        private CacheInterface $cache
    )
    {
    }
    
    public function render(): string
    {
        $output = $this->cache->getCachedValue('cachedWidget');
        if ($output !== null) {
            return $output;
        }
        // ...        
    }
}
```

We've avoided unnecessary inheritance and used `CacheInterface` in the
`CacheWidget` to reduce coupling.  You can replace cache implementation
without changing `CachedWidget` so it's becoming more stable. The less edits
are made to the code, the less chance of breaking it.

The `CacheInterface` here is a dependency: a contract our object needs to
function. In other words, our object depends on the contract.

The process of putting an instance of a contract into an object
(`CachedWidget`) is called dependency injection.  There are many ways to
perform it:

- Constructor injection. Best for mandatory dependencies.
- Method injection. Best for optional dependencies.
- Property injection. Better to be avoided in PHP except maybe data transfer
  objects.

### Why use private properties

In the composition example above, note that the `$cache` property is
declared as `private`.

This approach embraces composition by ensuring objects have well-defined
interfaces for interaction rather than direct property access, making the
code more maintainable and less prone to certain types of mistakes.

This design choice provides several benefits:

- **Encapsulation**: Private properties with getters/setters allow you to
  control access and make future changes without breaking existing code.
- **Data integrity**: Setters can validate, normalize, or format values
  before storing them, ensuring properties contain valid data.
- **Immutability**: Private properties enable immutable object patterns
  where setter `with*()` methods return new instances rather than modifying
  the current one.
- **Flexibility**: You can create read-only or write-only properties or add
  additional logic to property access later.


## DI container

Injecting basic dependencies is straightforward. You're choosing a place
where you don't care about dependencies, which is usually an action handler,
which you aren't going to unit-test ever, create instances of dependencies
needed and pass these to dependent classes.

It works well when there are few dependencies overall and when there are no
nested dependencies. When there are many and each dependency has
dependencies itself, instantiating the whole hierarchy becomes a tedious
process, which requires lots of code and may lead to hardly debuggable
mistakes.

Additionally, lots of dependencies, such as certain third-party API
wrappers, are the same for any class using it.  So it makes sense to:

- Define how to instantiate such common dependencies.
- Instantiate them when required and only once per request.

That's what dependency containers are for.

A dependency injection (DI) container is an object that knows how to
instantiate and configure objects and all objects they depend on.

Yii provides the DI container feature through the
[yiisoft/di](https://github.com/yiisoft/di) package and
[yiisoft/injector](https://github.com/yiisoft/injector) package.

> [!NOTE]
> The container contains only shared instances. If you need a factory, use the dedicated
> [yiisoft/factory](https://github.com/yiisoft/factory) package.

> [!TIP]
> [Martin Fowler's article](https://martinfowler.com/articles/injection.html) has well
> explained why DI container is useful. Here we will mainly explain the usage of the DI container provided by Yii.

### Configuring container

Because to create a new object you need its dependencies, you should
register them as early as possible.  You can do it in the application
configuration, `config/web.php`. For the following service:

```php
final class MyService implements MyServiceInterface
{
    public function __construct(int $amount)
    {
    }

    public function setDiscount(int $discount): void
    {
    
    }
}
```

configuration could be:

```php
return [
    MyServiceInterface::class => [
        'class' => MyService::class,
        '__construct()' => [42],
        'setDiscount()' => [10],
    ],
];
```

That's equal to the following:

```php
$myService = new MyService(42);
$myService->setDiscount(10);
```

You can provide arguments with names as well:

```php
return [
    MyServiceInterface::class => [
        'class' => MyService::class,
        '__construct()' => ['amount' => 42],
        'setDiscount()' => ['discount' => 10],
    ],
];
```

That's basically it. You define a map of interfaces to classes and define
how to configure them. When an interface is requested in constructor or
elsewhere, container creates an instance of a class and configures it as per
the configuration:

```php
final class MyAction
{
    public function __construct(
        private readonly MyServiceInterface $myService
    ) {
    }
    
    public function __invoke() 
    {
        $this->myService->doSomething();
    }
}
```

There are extra methods of declaring dependency configuration.

For simplest cases where there are no custom values needed and all the
constructor dependencies could be obtained from a container, you can use a
class name as a value.

```php
interface EngineInterface
{
    
}

final class EngineMarkOne implements EngineInterface
{
    public function __construct(CacheInterface $cache) {
    }   
}
```

In the above example, if we already have cache defined in the container,
nothing besides the class name is needed:

```php
return [
    // declare a class for an interface, resolve dependencies automatically
    EngineInterface::class => EngineMarkOne::class,
];
```

If you have a dependency that has public properties, you can configure it as
well.


```php
final class NameProvider
{
    public string $name;
}
```

Here's how to do it for the example above:

```php
NameProvider::class => [
    'class' => NameProvider::class, 
    '$name' => 'Alex',
],
```

In this example, you may notice `NameProvider` specified twice. The key is
what you may request as dependency and the value is how to create it.

If the configuration is tricky and requires some logic, a closure can be
used:

```php
MyServiceInterface::class => static function(ContainerInterface $container) {
    return new MyService($container->get('db'));
},
```

Additionally, to `ContainerInterface`, you can request any registered
service directly as a closure parameter.  The injector will automatically
resolve and inject these:

```php
MyServiceInterface::class => static function(ConnectionInterface $db) {
    return new MyService($db);
},
```

It's possible to use a static method call:

```php
MyServiceInterface::class => [MyFactory::class, 'create'],
```

Or an instance of an object:

```php
MyServiceInterface::class => new MyService(),
```

### Injecting dependencies properly

Directly referencing a container in a class is a bad idea since the code
becomes non-generic, coupled to the container interface and, what's worse,
dependencies are becoming hidden.  Because of that, Yii inverts the control
by automatically injecting objects from a container in some constructors and
methods based on method argument types.

This is primarily done in constructor and handing method of action handlers:

```php
use \Yiisoft\Cache\CacheInterface;

final readonly class MyController
{
    public function __construct(
        private CacheInterface $cache
    )
    {
        $this->cache = $cache;    
    }

    public function actionDashboard(RevenueReport $report)
    {
        $reportData = $this->cache->getOrSet('revenue_report', function() use ($report) {
            return $report->getData();               
        });

        return $this->render('dashboard', [
           'reportData' => $reportData,
        ]);
    }
}
```

Since it's [yiisoft/injector](https://github.com/yiisoft/injector) that
instantiates and calls action handler, it checks the constructor and method
argument types, gets dependencies of these types from a container and passes
them as arguments. That's usually called auto-wiring. It happens for
sub-dependencies as well, that's if you don't give dependency explicitly,
the container would check if it has such a dependency first.  It's enough to
declare a dependency you need, and it would be got from a container
automatically.


## Referensi

- [Inversion of Control Containers and the Dependency Injection pattern by
  Martin Fowler](https://martinfowler.com/articles/injection.html)

---

## File: src/id/guide/concept/events.md

# Event

Events allow you to run custom code at certain execution points without
changing the code that emits the event.  You attach a custom code called a
listener to an event. When the event is dispatched, the listener is
executed.

For example, when a user signs up, you need to send a welcome email. You can
do it in `SignupService`.  Later, when you also need to resize the user's
avatar image, the service has to know about that too.

A cleaner flow is to dispatch a `UserSignedUp` event from
`SignupService`. The welcome email sender and the avatar processor listen to
this event. Additional signup-related work can be added by registering
another listener.

Yii uses [yiisoft/yii-event](https://github.com/yiisoft/yii-event) for
application event configuration. It builds on the
[yiisoft/event-dispatcher](https://github.com/yiisoft/event-dispatcher)
package, which provides a [PSR-14](https://www.php-fig.org/psr/psr-14/)
compatible event dispatcher.

## Event classes

An event is an object. It usually contains data that listeners need:

```php
final readonly class UserSignedUp
{
    public function __construct(
        public SignupForm $form,
    ) {}
}
```

## Event listeners

An event listener is a [PHP
callable](https://www.php.net/manual/en/language.types.callable.php) that
receives an event:

```php
static function (UserSignedUp $event): void {
    // Send a welcome email.
}
```

You can also use an invokable class:

```php
final readonly class WelcomeEmailSender
{
    public function __invoke(UserSignedUp $event): void
    {
        // Send a welcome email.
    }
}
```

## Configuring event listeners

In an application, configure listeners in:

- `config/events.php` for all application types.
- `config/events-web.php` for web application events.
- `config/events-console.php` for console application events.

The configuration is an array where keys are event class names and values
are lists of listeners:

```php
<?php

declare(strict_types=1);

use App\Event\UserSignedUp;
use App\EventListener\WelcomeEmailSender;
use App\Service\AvatarProcessor;

return [
    UserSignedUp::class => [
        WelcomeEmailSender::class,
        static fn (UserSignedUp $event, AvatarProcessor $avatarProcessor) => $avatarProcessor->resize($event->form),
    ],
];
```

The listener may be a closure, a callable array, an invokable object, an
invokable class name, or a DI alias.  For closure and callable array
listeners, parameters after the first event parameter are resolved from the
DI container.  Invokable class names are instantiated by the container.

Dependencies are resolved when the event is dispatched.

## Dispatching events

To dispatch an event, use `Psr\EventDispatcher\EventDispatcherInterface`:

```php
use Psr\EventDispatcher\EventDispatcherInterface;

final readonly class SignupService
{
    public function __construct(
        private EventDispatcherInterface $eventDispatcher,
    ) {}

    public function signup(SignupForm $form): void
    {
        // Sign up the user.

        $this->eventDispatcher->dispatch(new UserSignedUp($form));
    }
}
```

The dispatcher asks a listener provider for listeners that match the event
and calls them one by one.

## Event listener order

When several listeners are configured for the same event, they are called in
the order they are listed in the config.  If an event implements
`Psr\EventDispatcher\StoppableEventInterface`, the dispatcher checks
`isPropagationStopped()` before calling the next listener. When it returns
`true`, the dispatcher stops processing the event.

Keep listeners independent where possible. Ordering is useful for technical
needs, but business logic is usually easier to maintain when each listener
can run on its own.

## Event hierarchy

Events don't have names or wildcard matching. Event class names, interfaces,
and inheritance can be used when one listener should handle several related
events:

```php
interface DocumentEvent
{
}

final readonly class BeforeDocumentProcessed implements DocumentEvent
{
}

final readonly class AfterDocumentProcessed implements DocumentEvent
{
}
```

With the interface, you can listen to all document-related events:

```php
use Yiisoft\EventDispatcher\Provider\ListenerCollection;
use Yiisoft\EventDispatcher\Provider\Provider;

$listeners = (new ListenerCollection())
    ->add(static function (DocumentEvent $event): void {
        // Log document events.
    });

$provider = new Provider($listeners);
```

## Manual listener provider setup

In an application, use event configuration. For package-level code or tests,
you can create a listener provider manually:

```php
use Yiisoft\EventDispatcher\Dispatcher\Dispatcher;
use Yiisoft\EventDispatcher\Provider\ListenerCollection;
use Yiisoft\EventDispatcher\Provider\Provider;

$listeners = (new ListenerCollection())
    ->add(static function (UserSignedUp $event): void {
        // Send a welcome email.
    });

$provider = new Provider($listeners);
$dispatcher = new Dispatcher($provider);

$dispatcher->dispatch(new UserSignedUp($form));
```

`ListenerCollection::add()` returns a new collection instance. Assign the result when building a collection step by step:

```php
$listeners = new ListenerCollection();
$listeners = $listeners->add(
    static function (UserSignedUp $event): void {
        // Send a welcome email.
    },
    UserSignedUp::class,
);
```

---

## File: src/id/guide/concept/immutability.md

# Immutability

Immutability means an object's state cannot change after it has been
created.  Instead of modifying an instance, you create a new instance with
the desired changes.  This approach is common for value objects such as
Money, IDs, and DTOs. It helps to avoid accidental side effects: methods
cannot silently change shared state, which makes code easier to reason
about.

## Mutable pitfalls (what we avoid)

```php
// A shared base query built once and reused:
$base = Post::find()->where(['status' => Post::STATUS_PUBLISHED]);

// Somewhere deep in the code we only need one post:
$one = $base->limit(1)->one(); // mutates the underlying builder (sticky limit!)

// Later we reuse the same $base expecting a full list:
$list = $base->orderBy(['created_at' => SORT_DESC])->all();
// Oops: still limited to 1 because the previous limit(1) modified $base.
```

## Creating an immutable object in PHP

There is no direct way to modify an instance, but you can use clone to
create a new instance with the desired changes.  That is what `with*`
methods do.

```
/* Detailed source-code truncated for AI context efficiency. */
```

- We mark the class `final` to prevent subclass mutations; alternatively,
  design for extension carefully.
- Validate in the constructor and `with*` methods so every instance is
  always valid.

> [!TIP]
> If you define a simple DTO, you can use modern PHP `readonly` and leave properties `public`. The `readonly` keyword
> would ensure that the properties cannot be modified after the object is created.

## Using clone (and why it is inexpensive)

PHP's clone performs a shallow copy of the object. For immutable value
objects that contain only scalars or other immutable objects, shallow
cloning is enough and fast. In modern PHP, cloning small value objects is
inexpensive in both time and memory.

If your object holds mutable sub-objects that must also be copied, implement
`__clone` to deep-clone them:

```php
final class Order
{
    public function __construct(
        private Money $total
    ) {}
    
    public function total(): Money 
    {
        return $this->total;
    }

    public function __clone(): void
    {
        // Money is immutable in our example, so a deep clone is not required.
        // If it were mutable, you could do: $this->total = clone $this->total;
    }

    public function withTotal(Money $total): self
    {
        $clone = clone $this;
        $clone->total = $total;
        return $clone;
    }
}
```

## Usage style

- Build a value object once and pass it around. If you need a change, use a
  `with*` method that returns a new instance.
- Prefer scalar/immutable fields inside immutable objects; if a field can
  mutate, isolate it and deep-clone in `__clone` when needed.

Immutability aligns well with Yii's preference for predictable,
side-effect-free code and makes services, caching, and configuration more
robust.

---

## File: src/id/guide/caching/data.md

# Caching data

Caching data adalah tentang menyimpan beberapa variabel PHP ke dalam cache
dan mengambilnya kembali dari cache.
Ini juga menjadi fondasi untuk fitur caching yang lebih lanjut, seperti
[caching halaman](page.md).

Untuk menggunakan cache, pasang paket
[yiisoft/cache](https://github.com/yiisoft/cache):

```shell
composer require yiisoft/cache
```

Kode berikut adalah pola penggunaan umum caching data, di mana `$cache`
merujuk ke
instance `Cache` dari paket tersebut:

```php
public function getTopProducts(\Yiisoft\Cache\CacheInterface $cache): array
{
    $key = ['top-products', $count = 10];
    
    // Try retrieving $data from cache.
    $data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) {
        // Can't find $data in a cache, calculate it from scratch.
        return getTopProductsFromDatabase($count);
    }, 3600);
    
    return $data;
}
```

Ketika cache memiliki data yang terkait dengan `$key`, ia akan mengembalikan
nilai yang di-cache.
Jika tidak, ia akan mengeksekusi fungsi anonim yang diberikan untuk
menghitung nilai yang akan di-cache dan dikembalikan.

Jika fungsi anonim membutuhkan beberapa data dari scope luar, Anda dapat
meneruskannya menggunakan pernyataan `use`.

## Cache handlers

Layanan cache menggunakan handler cache yang kompatibel dengan
[PSR-16](https://www.php-fig.org/psr/psr-16/) yang merepresentasikan
berbagai
penyimpanan cache, seperti memori, berkas, dan basis data.

Yii menyediakan handler berikut:

- `NullCache` — placeholder cache yang tidak melakukan caching nyata. Tujuan
  handler ini adalah menyederhanakan
    kode yang perlu memeriksa ketersediaan cache. Misalnya, selama
  pengembangan atau jika server tidak memiliki
    dukungan cache, Anda dapat mengonfigurasi layanan cache untuk
  menggunakan handler ini.
    Saat Anda mengaktifkan dukungan cache nyata, Anda dapat beralih
  menggunakan handler cache yang sesuai.
    Pada kedua kasus, Anda dapat menggunakan kode yang sama tanpa
  pemeriksaan tambahan.
- `ArrayCache` — menyediakan caching hanya untuk permintaan saat ini dengan
  menyimpan nilai dalam sebuah array.
- [APCu](https://github.com/yiisoft/cache-apcu) — menggunakan ekstensi PHP
  [APC](https://secure.php.net/manual/en/book.apc.php).
    Ini bisa dianggap sebagai opsi tercepat saat berurusan dengan cache
  untuk aplikasi terpusat (mis., satu
    server, tanpa load balancer khusus, dll.).
- [Database](https://github.com/yiisoft/cache-db) — menggunakan tabel basis
  data untuk menyimpan data yang di-cache.
- [File](https://github.com/yiisoft/cache-file) — menggunakan berkas standar
  untuk menyimpan data yang di-cache. Ini sangat cocok
    untuk menyimpan potongan data besar, seperti konten halaman.
- [Memcached](https://github.com/yiisoft/cache-memcached) — uses a PHP
  [memcached](https://secure.php.net/manual/en/book.memcached.php)
  extension. You can consider this option as the fastest one when dealing
  with cache in a distributed application
  (e.g., with several servers, load balancers, etc.)
- [Wincache](https://github.com/yiisoft/cache-wincache) — uses PHP [WinCache](https://iis.net/downloads/microsoft/wincache-extension)
  ([see also](https://secure.php.net/manual/en/book.wincache.php)) extension.

[Anda dapat menemukan lebih banyak handler di
packagist.org](https://packagist.org/providers/psr/simple-cache-implementation).

> [!TIP]
> Anda dapat menggunakan penyimpanan cache yang berbeda dalam aplikasi yang sama. Strategi umum adalah:
> - Gunakan penyimpanan cache berbasis memori untuk menyimpan data kecil tetapi sering digunakan (mis., statistik)
> - Gunakan penyimpanan cache berbasis berkas atau basis data untuk menyimpan data besar dan jarang digunakan (mis., konten halaman)

Handler cache biasanya disetel dalam [dependency injection
container](../concept/di-container.md) sehingga dapat
dikonfigurasi dan diakses secara global.

Karena semua handler cache mendukung kumpulan API yang sama, Anda dapat
menukar handler cache yang digunakan
dengan yang lain. Anda dapat melakukannya dengan mengonfigurasi ulang
aplikasi tanpa mengubah kode yang menggunakan cache.

### Cache keys

Sebuah kunci mengidentifikasi secara unik setiap item data yang disimpan di
cache. Saat Anda menyimpan sebuah item data,
Anda harus menentukan kunci untuknya. Nantinya, ketika Anda mengambil item
data tersebut, Anda perlu memberikan
kunci yang sesuai.

Anda dapat menggunakan string atau nilai arbitrer sebagai kunci
cache. Ketika kunci bukan string, ia akan
diserialisasi menjadi string secara otomatis.

Strategi umum dalam mendefinisikan kunci cache adalah menyertakan semua
faktor penentu dalam bentuk array.

Ketika aplikasi yang berbeda menggunakan penyimpanan cache yang sama, Anda
harus menentukan prefiks kunci cache yang unik
untuk setiap aplikasi guna menghindari konflik kunci cache.
Anda dapat melakukannya dengan menggunakan dekorator
`\Yiisoft\Cache\PrefixedCache`:

```php
$arrayCacheWithPrefix = new \Yiisoft\Cache\PrefixedCache(new \Yiisoft\Cache\ArrayCache(), 'myapp_');
$cache = new \Yiisoft\Cache\Cache($arrayCacheWithPrefix);
```

### Cache expiration

Item data yang disimpan di cache akan tetap di sana selamanya kecuali
dihapus karena beberapa kebijakan
caching. Misalnya, ruang cache penuh dan penyimpanan cache menghapus data
tertua.
Untuk mengubah perilaku ini, Anda dapat menyetel parameter TTL saat
memanggil metode untuk menyimpan item data:

```php
$ttl = 3600;
$data = $cache->getOrSet($key, function (\Psr\SimpleCache\CacheInterface $cache) use ($count) {
return getTopProductsFromDatabase($count);
}, $ttl);
```

Parameter `$ttl` menunjukkan berapa detik item data dapat tetap valid di
cache. Ketika Anda mengambil
item data tersebut, jika waktu kedaluwarsanya telah lewat, metode akan
mengeksekusi fungsi dan menyetel nilai yang dihasilkan
ke dalam cache.

You may set the default TTL for the cache:

```php
$cache = new \Yiisoft\Cache\Cache($arrayCache, 60 * 60); // 1 hour
```

Selain itu, Anda dapat menginvalidasi kunci cache secara eksplisit:

```php
$cache->remove($key);
```

### Invalidation dependencies

Selain pengaturan kedaluwarsa, perubahan pada yang disebut sebagai
**ketergantungan invalidasi** juga dapat menginvalidasi item data yang
di-cache.
Misalnya, `\Yiisoft\Cache\Dependency\FileDependency` merepresentasikan
ketergantungan pada waktu modifikasi sebuah berkas.
Ketika ketergantungan ini berubah, itu berarti ada sesuatu yang memodifikasi
berkas terkait.
Akibatnya, konten berkas yang usang yang ditemukan di cache harus
diinvalidasi.

Ketergantungan cache adalah objek dari kelas turunan
`\Yiisoft\Cache\Dependency\Dependency`. Ketika Anda
menyimpan sebuah item data ke cache, Anda dapat menyertakan objek
ketergantungan cache terkait. Contohnya,

```php
/**
 * @var callable $callable
 * @var \Yiisoft\Cache\CacheInterface $cache
 */

use Yiisoft\Cache\Dependency\TagDependency;

// Set many cache values marking both with a tag.
$cache->getOrSet('item_42_price', $callable, null, new TagDependency('item_42'));
$cache->getOrSet('item_42_total', $callable, 3600, new TagDependency('item_42'));

// Trigger invalidation by tag.
TagDependency::invalidate($cache, 'item_42');
```

Berikut ringkasan ketergantungan cache yang tersedia:

- `\Yiisoft\Cache\Dependency\ValueDependency`: menginvalidasi cache ketika
  nilai yang ditentukan berubah.
- `\Yiisoft\Cache\Dependency\CallbackDependency`: menginvalidasi cache
  ketika hasil dari callback PHP yang ditentukan
    berbeda.
- `\Yiisoft\Cache\Dependency\FileDependency`: menginvalidasi cache ketika
  waktu modifikasi terakhir berkas berbeda.
- `\Yiisoft\Cache\Dependency\TagDependency`: mengaitkan item data yang
  di-cache dengan satu atau banyak tag. Anda dapat menginvalidasi
    item data yang di-cache dengan tag tertentu dengan memanggil
  `TagDependency::invalidate()`.

Anda dapat mengombinasikan banyak ketergantungan menggunakan
`\Yiisoft\Cache\Dependency\AnyDependency` atau
`\Yiisoft\Cache\Dependency\AllDependencies`.

Untuk mengimplementasikan ketergantungan Anda sendiri, turunkan dari
`\Yiisoft\Cache\Dependency\Dependency`.

### Cache stampede prevention

[Cache stampede](https://en.wikipedia.org/wiki/Cache_stampede) adalah jenis
kegagalan berantai yang dapat terjadi ketika sistem komputasi paralel masif
dengan mekanisme cache berada di bawah beban tinggi.
Perilaku ini terkadang juga disebut dog-piling.

The `\Yiisoft\Cache\Cache` uses a built-in "Probably early expiration"
algorithm that prevents cache stampede.  This algorithm randomly fakes a
cache miss for one user while others are still served the cached value.  You
can control its behavior with the fifth optional parameter of `getOrSet()`,
which is a float value called `$beta`.  By default, beta is `1.0`, which is
usually enough.  The higher the value, the earlier cache will be re-created.

```php
/**
 * @var mixed $key
 * @var callable $callable
 * @var \DateInterval $ttl
 * @var \Yiisoft\Cache\CacheInterface $cache
 * @var \Yiisoft\Cache\Dependency\Dependency $dependency
 */

$beta = 2.0;
$cache->getOrSet($key, $callable, $ttl, $dependency, $beta);
```

---

## File: src/id/guide/caching/overview.md

# Caching

Caching adalah cara yang murah dan efektif untuk meningkatkan performa
aplikasi.
Dengan menyimpan data yang relatif statis di cache dan menyajikannya dari
cache saat diminta,
aplikasi menghemat waktu yang sebaliknya diperlukan untuk menghasilkan data
dari awal setiap kali.

Caching dapat terjadi pada berbagai level dan lokasi dalam sebuah
aplikasi. Di sisi server, pada level rendah,
cache dapat digunakan untuk menyimpan data dasar, seperti daftar artikel
terbaru yang diambil dari basis data;
dan pada level yang lebih tinggi, cache dapat digunakan untuk menyimpan
fragmen atau seluruh halaman web, seperti hasil rendering
artikel terbaru. Di sisi klien, Anda dapat menggunakan HTTP caching untuk
menyimpan konten halaman yang terakhir dikunjungi
di cache browser.

Yii mendukung semua mekanisme caching berikut:

* [Data caching](data.md)
* [Fragment caching](fragment.md)
* [Page caching](page.md)
* [HTTP caching](http.md)